diff options
Diffstat (limited to 'java')
221 files changed, 3973 insertions, 2608 deletions
diff --git a/java/compiler/impl/compiler-impl.iml b/java/compiler/impl/compiler-impl.iml index 08d3ca179fc0..c6e3e4f81eab 100644 --- a/java/compiler/impl/compiler-impl.iml +++ b/java/compiler/impl/compiler-impl.iml @@ -28,6 +28,7 @@ <orderEntry type="module" module-name="testFramework-java" scope="TEST" /> <orderEntry type="module" module-name="jps-model-impl" /> <orderEntry type="module" module-name="java-analysis-impl" /> + <orderEntry type="module" module-name="xml" /> </component> <component name="copyright"> <Base> diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index 03ff006eea40..01da3bc62541 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -128,8 +128,6 @@ public class BuildManager implements ApplicationComponent{ private static final String COMPILER_PROCESS_JDK_PROPERTY = "compiler.process.jdk"; public static final String SYSTEM_ROOT = "compile-server"; public static final String TEMP_DIR_NAME = "_temp_"; - private static final int MAKE_TRIGGER_DELAY = 300 /*300 ms*/; - private static final int DOCUMENT_SAVE_TRIGGER_DELAY = 1500 /*1.5 sec*/; private final boolean IS_UNIT_TEST_MODE; private static final String IWS_EXTENSION = ".iws"; private static final String IPR_EXTENSION = ".ipr"; @@ -161,7 +159,7 @@ public class BuildManager implements ApplicationComponent{ private final BuildManagerPeriodicTask myAutoMakeTask = new BuildManagerPeriodicTask() { @Override protected int getDelay() { - return Registry.intValue("compiler.automake.trigger.delay", MAKE_TRIGGER_DELAY); + return Registry.intValue("compiler.automake.trigger.delay"); } @Override @@ -173,7 +171,7 @@ public class BuildManager implements ApplicationComponent{ private final BuildManagerPeriodicTask myDocumentSaveTask = new BuildManagerPeriodicTask() { @Override protected int getDelay() { - return Registry.intValue("compiler.document.save.trigger.delay", DOCUMENT_SAVE_TRIGGER_DELAY); + return Registry.intValue("compiler.document.save.trigger.delay"); } private final Semaphore mySemaphore = new Semaphore(); @@ -624,7 +622,7 @@ public class BuildManager implements ApplicationComponent{ data = new ProjectData(new SequentialTaskExecutor(PooledThreadExecutor.INSTANCE)); myProjectDataMap.put(projectPath, data); } - if (isRebuild || (isAutomake && Registry.is("compiler.automake.force.fs.rescan", false))) { + if (isRebuild || (isAutomake && Registry.is("compiler.automake.force.fs.rescan"))) { data.dropChanges(); } if (IS_UNIT_TEST_MODE) { diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactUtil.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactUtil.java index 5752c3f5f77b..3fcfc8df5529 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactUtil.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactUtil.java @@ -26,10 +26,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.packaging.artifacts.Artifact; -import com.intellij.packaging.artifacts.ArtifactManager; -import com.intellij.packaging.artifacts.ArtifactProperties; -import com.intellij.packaging.artifacts.ArtifactType; +import com.intellij.packaging.artifacts.*; import com.intellij.packaging.elements.*; import com.intellij.packaging.impl.elements.*; import com.intellij.util.PathUtil; @@ -599,5 +596,31 @@ public class ArtifactUtil { public static String suggestArtifactFileName(String artifactName) { return PathUtil.suggestFileName(artifactName, true, true); } + + @Nullable + public static Artifact addArtifact(@NotNull ModifiableArtifactModel artifactModel, + @NotNull ArtifactType type, + @NotNull ArtifactTemplate artifactTemplate) { + final ArtifactTemplate.NewArtifactConfiguration configuration = artifactTemplate.createArtifact(); + if (configuration == null) { + return null; + } + + final String baseName = configuration.getArtifactName(); + String name = baseName; + int i = 2; + while (artifactModel.findArtifact(name) != null) { + name = baseName + i; + i++; + } + + ArtifactType actualType = configuration.getArtifactType(); + if (actualType == null) { + actualType = type; + } + final ModifiableArtifact artifact = artifactModel.addArtifact(name, actualType, configuration.getRootElement()); + artifactTemplate.setUpArtifact(artifact, configuration); + return artifact; + } } diff --git a/java/compiler/impl/src/org/jetbrains/builtInWebServer/ArtifactWebServerRootsProvider.java b/java/compiler/impl/src/org/jetbrains/builtInWebServer/ArtifactWebServerRootsProvider.java new file mode 100644 index 000000000000..4733ca3747ec --- /dev/null +++ b/java/compiler/impl/src/org/jetbrains/builtInWebServer/ArtifactWebServerRootsProvider.java @@ -0,0 +1,39 @@ +package org.jetbrains.builtInWebServer; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.packaging.artifacts.ArtifactManager; +import com.intellij.util.PairFunction; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +final class ArtifactWebServerRootsProvider extends PrefixlessWebServerRootsProvider { + @Nullable + @Override + public PathInfo resolve(@NotNull String path, @NotNull Project project, @NotNull PairFunction<String, VirtualFile, VirtualFile> resolver) { + for (Artifact artifact : ArtifactManager.getInstance(project).getArtifacts()) { + VirtualFile root = artifact.getOutputFile(); + if (root != null) { + VirtualFile file = root.findFileByRelativePath(path); + if (file != null) { + return new PathInfo(file, root); + } + } + } + return null; + } + + @Nullable + @Override + public PathInfo getRoot(@NotNull VirtualFile file, @NotNull Project project) { + for (Artifact artifact : ArtifactManager.getInstance(project).getArtifacts()) { + VirtualFile root = artifact.getOutputFile(); + if (root != null && VfsUtilCore.isAncestor(root, file, true)) { + return new PathInfo(file, root); + } + } + return null; + } +}
\ No newline at end of file diff --git a/java/compiler/javac2/src/com/intellij/ant/Javac2.java b/java/compiler/javac2/src/com/intellij/ant/Javac2.java index 88095a9cdc36..e5b8aee7130a 100644 --- a/java/compiler/javac2/src/com/intellij/ant/Javac2.java +++ b/java/compiler/javac2/src/com/intellij/ant/Javac2.java @@ -466,7 +466,7 @@ public class Javac2 extends Javac { public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { classfileVersion[0] = version; } - }, 0); + }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); return classfileVersion[0]; } diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeContextViewAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeContextViewAction.java index 01d6fcc6e7e8..6214a9e44d7f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeContextViewAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeContextViewAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -17,14 +17,12 @@ package com.intellij.debugger.actions; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.JavaDebugProcess; -import com.intellij.debugger.settings.DebuggerDataViewsConfigurable; +import com.intellij.debugger.settings.JavaDebuggerSettings; import com.intellij.debugger.settings.NodeRendererSettings; -import com.intellij.debugger.settings.UserRenderersConfigurable; import com.intellij.idea.ActionsBundle; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.options.CompositeConfigurable; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.TabbedConfigurable; @@ -40,16 +38,9 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.border.EmptyBorder; -import java.util.ArrayList; import java.util.List; -/** - * User: lex - * Date: Sep 26, 2003 - * Time: 4:39:53 PM - */ public class CustomizeContextViewAction extends XDebuggerTreeActionBase { - @Override public void actionPerformed(AnActionEvent e) { perform(null, "", e); @@ -58,15 +49,11 @@ public class CustomizeContextViewAction extends XDebuggerTreeActionBase { @Override protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e) { final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext()); - Disposable disposable = Disposer.newDisposable(); - final CompositeConfigurable configurable = new TabbedConfigurable(disposable) { + SingleConfigurableEditor editor = new SingleConfigurableEditor(project, new TabbedConfigurable(disposable) { @Override protected List<Configurable> createConfigurables() { - ArrayList<Configurable> array = new ArrayList<Configurable>(); - array.add(new DebuggerDataViewsConfigurable(project)); - array.add(new UserRenderersConfigurable(project)); - return array; + return JavaDebuggerSettings.createDataViewsConfigurable(); } @Override @@ -89,13 +76,12 @@ public class CustomizeContextViewAction extends XDebuggerTreeActionBase { protected void createConfigurableTabs() { for (Configurable configurable : getConfigurables()) { JComponent component = configurable.createComponent(); - component.setBorder(new EmptyBorder(8,8,8,8)); + assert component != null; + component.setBorder(new EmptyBorder(8, 8, 8, 8)); myTabbedPane.addTab(configurable.getDisplayName(), component); } } - }; - - SingleConfigurableEditor editor = new SingleConfigurableEditor(project, configurable); + }); Disposer.register(editor.getDisposable(), disposable); editor.show(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java index 1db0ed60774e..4714ca49bd06 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java @@ -322,10 +322,15 @@ public class DebugProcessEvents extends DebugProcessImpl { myDebugProcessDispatcher.getMulticaster().processAttached(this); // breakpoints should be initialized after all processAttached listeners work - XDebugSession session = getSession().getXDebugSession(); - if (session != null) { - session.initBreakpoints(); - } + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + XDebugSession session = getSession().getXDebugSession(); + if (session != null) { + session.initBreakpoints(); + } + } + }); final String addressDisplayName = DebuggerBundle.getAddressDisplayName(getConnection()); final String transportName = DebuggerBundle.getTransportName(getConnection()); @@ -459,13 +464,18 @@ public class DebugProcessEvents extends DebugProcessImpl { if (requestHit && requestor instanceof Breakpoint) { // if requestor is a breakpoint and this breakpoint was hit, no matter its suspend policy - XDebugSession session = getSession().getXDebugSession(); - if (session != null) { - XBreakpoint breakpoint = ((Breakpoint)requestor).getXBreakpoint(); - if (breakpoint != null) { - ((XDebugSessionImpl)session).processDependencies(breakpoint); + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + XDebugSession session = getSession().getXDebugSession(); + if (session != null) { + XBreakpoint breakpoint = ((Breakpoint)requestor).getXBreakpoint(); + if (breakpoint != null) { + ((XDebugSessionImpl)session).processDependencies(breakpoint); + } + } } - } + }); } if(!requestHit || resumePreferred) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaBreakpointHandler.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaBreakpointHandler.java index ad2c881d1336..75897417bd2e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaBreakpointHandler.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaBreakpointHandler.java @@ -49,13 +49,17 @@ public class JavaBreakpointHandler extends XBreakpointHandler { if (javaBreakpoint != null) { final Breakpoint bpt = javaBreakpoint; BreakpointManager.addBreakpoint(bpt); - // must use invoke to stay in the current request, - // otherwise dependent breakpoints do not get enabled on not-suspending parents hit - myProcess.getManagerThread().invoke(new DebuggerCommandImpl() { + // use schedule not to block initBreakpoints + myProcess.getManagerThread().schedule(new DebuggerCommandImpl() { @Override protected void action() throws Exception { bpt.createRequest(myProcess); } + + @Override + public Priority getPriority() { + return Priority.HIGH; + } }); } } @@ -64,12 +68,17 @@ public class JavaBreakpointHandler extends XBreakpointHandler { public void unregisterBreakpoint(@NotNull final XBreakpoint breakpoint, boolean temporary) { final Breakpoint javaBreakpoint = BreakpointManager.getJavaBreakpoint(breakpoint); if (javaBreakpoint != null) { - // must use invoke to stay in the current request, see comment in registerBreakpoint - myProcess.getManagerThread().invoke(new DebuggerCommandImpl() { + // use schedule not to block initBreakpoints + myProcess.getManagerThread().schedule(new DebuggerCommandImpl() { @Override protected void action() throws Exception { javaBreakpoint.delete(); } + + @Override + public Priority getPriority() { + return Priority.HIGH; + } }); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaExecutionStack.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaExecutionStack.java index 793438ebbe05..f2cb40008ad5 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaExecutionStack.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaExecutionStack.java @@ -26,6 +26,7 @@ import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl; import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.debugger.ui.impl.watch.MethodsTracker; +import com.intellij.debugger.ui.impl.watch.NodeManagerImpl; import com.intellij.icons.AllIcons; import com.intellij.xdebugger.frame.XExecutionStack; import com.sun.jdi.ThreadReference; @@ -43,6 +44,7 @@ import java.util.Iterator; public class JavaExecutionStack extends XExecutionStack { private final ThreadReferenceProxyImpl myThreadProxy; private final DebugProcessImpl myDebugProcess; + private final NodeManagerImpl myNodeManager; private volatile JavaStackFrame myTopFrame; private boolean myTopFrameReady = false; private final MethodsTracker myTracker = new MethodsTracker(); @@ -51,6 +53,7 @@ public class JavaExecutionStack extends XExecutionStack { super(calcRepresentation(threadProxy), calcIcon(threadProxy, current)); myThreadProxy = threadProxy; myDebugProcess = debugProcess; + myNodeManager = myDebugProcess.getXdebugProcess().getNodeManager(); if (current) { myTopFrame = calcTopFrame(); } @@ -81,7 +84,7 @@ public class JavaExecutionStack extends XExecutionStack { try { StackFrameProxyImpl frame = myThreadProxy.frame(0); if (frame != null) { - return new JavaStackFrame(frame, myDebugProcess, myTracker); + return new JavaStackFrame(frame, myDebugProcess, myTracker, myNodeManager); } } catch (EvaluateException e) { @@ -180,7 +183,7 @@ public class JavaExecutionStack extends XExecutionStack { @Override public void contextAction() throws Exception { if (myStackFramesIterator.hasNext()) { - JavaStackFrame frame = new JavaStackFrame(myStackFramesIterator.next(), myDebugProcess, myTracker); + JavaStackFrame frame = new JavaStackFrame(myStackFramesIterator.next(), myDebugProcess, myTracker, myNodeManager); if (DebuggerSettings.getInstance().SHOW_LIBRARY_STACKFRAMES || (!frame.getDescriptor().isSynthetic() && !frame.getDescriptor().isInLibraryContent())) { if (++myAdded > mySkip) { myContainer.addStackFrames(Arrays.asList(frame), false); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java index bcd8257736c2..db28c4bf34a7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java @@ -71,9 +71,12 @@ public class JavaStackFrame extends XStackFrame { private static final JavaFramesListRenderer FRAME_RENDERER = new JavaFramesListRenderer(); private JavaDebuggerEvaluator myEvaluator = null; - public JavaStackFrame(@NotNull StackFrameProxyImpl stackFrameProxy, @NotNull DebugProcessImpl debugProcess, MethodsTracker tracker) { + public JavaStackFrame(@NotNull StackFrameProxyImpl stackFrameProxy, + @NotNull DebugProcessImpl debugProcess, + @NotNull MethodsTracker tracker, + @NotNull NodeManagerImpl nodeManager) { myDebugProcess = debugProcess; - myNodeManager = debugProcess.getXdebugProcess().getNodeManager(); + myNodeManager = nodeManager; myDescriptor = new StackFrameDescriptorImpl(stackFrameProxy, tracker); myDescriptor.setContext(null); myDescriptor.updateRepresentation(null, DescriptorLabelListener.DUMMY_LISTENER); @@ -311,8 +314,7 @@ public class JavaStackFrame extends XStackFrame { final Collection<Value> argValues = frame.getArgumentValues(); int index = 0; for (Value argValue : argValues) { - final ArgumentValueDescriptorImpl descriptor = myNodeManager.getArgumentValueDescriptor(null, index++, argValue, null); - children.add(JavaValue.create(descriptor, evaluationContext, myNodeManager)); + children.add(createArgumentValue(index++, argValue, null, evaluationContext)); } node.setMessage(MessageDescriptor.LOCAL_VARIABLES_INFO_UNAVAILABLE.getLabel(), XDebuggerUIConstants.INFORMATION_MESSAGE_ICON, SimpleTextAttributes.REGULAR_ATTRIBUTES, null); //myChildren.add(myNodeManager.createMessageNode(MessageDescriptor.LOCAL_VARIABLES_INFO_UNAVAILABLE)); @@ -323,9 +325,7 @@ public class JavaStackFrame extends XStackFrame { try { final Map<DecompiledLocalVariable, Value> values = LocalVariablesUtil.fetchValues(frame.getStackFrame(), decompiled); for (DecompiledLocalVariable var : decompiled) { - final Value value = values.get(var); - final ArgumentValueDescriptorImpl descriptor = myNodeManager.getArgumentValueDescriptor(null, var.getSlot(), value, var.getName()); - children.add(JavaValue.create(descriptor, evaluationContext, myNodeManager)); + children.add(createArgumentValue(var.getSlot(), values.get(var), var.getName(), evaluationContext)); } } catch (Exception ex) { @@ -339,6 +339,13 @@ public class JavaStackFrame extends XStackFrame { } } + private JavaValue createArgumentValue(int index, Value value, String name, EvaluationContextImpl evaluationContext) { + ArgumentValueDescriptorImpl descriptor = myNodeManager.getArgumentValueDescriptor(null, index, value, name); + // setContext is required to calculate correct name + descriptor.setContext(evaluationContext); + return JavaValue.create(descriptor, evaluationContext, myNodeManager); + } + protected void superBuildVariables(final EvaluationContextImpl evaluationContext, XValueChildrenList children) throws EvaluateException { final StackFrameProxyImpl frame = getStackFrameProxy(); for (final LocalVariableProxyImpl local : frame.visibleVariables()) { @@ -354,6 +361,6 @@ public class JavaStackFrame extends XStackFrame { @Nullable @Override public Object getEqualityObject() { - return getStackFrameProxy().hashCode(); + return myDescriptor.getMethod(); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueMarker.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueMarker.java index be1b8fae60b9..6a555a87063a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueMarker.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueMarker.java @@ -30,8 +30,7 @@ public class JavaValueMarker extends XValueMarkerProvider<JavaValue, ObjectRefer @Override public boolean canMark(@NotNull JavaValue value) { - Value obj = value.getDescriptor().getValue(); - return obj instanceof ObjectReference; + return value.getDescriptor().canMark(); } @Override diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerImpl.java index 576f781dc368..c1f1f87db1a9 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.debugger.engine; +import com.intellij.debugger.engine.events.DebuggerCommandImpl; import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; import com.intellij.openapi.diagnostic.Logger; import com.sun.jdi.InternalException; @@ -296,7 +297,7 @@ public class SuspendManagerImpl implements SuspendManager { } } - private void processVote(SuspendContextImpl suspendContext) { + private void processVote(final SuspendContextImpl suspendContext) { LOG.assertTrue(suspendContext.myVotesToVote > 0); suspendContext.myVotesToVote--; @@ -305,7 +306,18 @@ public class SuspendManagerImpl implements SuspendManager { } if(suspendContext.myVotesToVote == 0) { if(suspendContext.myIsVotedForResume) { - resume(suspendContext); + // resume in a separate request to allow other requests be processed (e.g. dependent bpts enable) + myDebugProcess.getManagerThread().schedule(new DebuggerCommandImpl() { + @Override + protected void action() throws Exception { + resume(suspendContext); + } + + @Override + public Priority getPriority() { + return Priority.HIGH; + } + }); } else { if (LOG.isDebugEnabled()) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java index 69cbb140be86..2569559d2d11 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java @@ -30,7 +30,10 @@ import com.intellij.debugger.engine.evaluation.EvaluateRuntimeException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.openapi.diagnostic.Logger; -import com.sun.jdi.*; +import com.sun.jdi.ClassType; +import com.sun.jdi.Method; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; import java.util.ArrayList; import java.util.List; @@ -127,14 +130,16 @@ public class MethodEvaluator implements Evaluator { _refType = ((ClassType)referenceType).superclass(); } Method jdiMethod = DebuggerUtils.findMethod(_refType, myMethodName, signature); - if (jdiMethod == null || jdiMethod.argumentTypes().size() != args.size()) { + if (signature == null) { + // we know nothing about expected method's signature, so trying to match my method name and parameter count // dummy matching, may be improved with types matching later - List<Method> methods = _refType.methodsByName(myMethodName); - for (Method method : methods) { - List<Type> types = method.argumentTypes(); - if (types.size() == args.size()) { - jdiMethod = method; - break; + // IMPORTANT! using argumentTypeNames() instead of argumentTypes() to avoid type resolution inside JDI, which may be time-consuming + if (jdiMethod == null || jdiMethod.argumentTypeNames().size() != args.size()) { + for (Method method : _refType.methodsByName(myMethodName)) { + if (method.argumentTypeNames().size() == args.size()) { + jdiMethod = method; + break; + } } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java index f5404cd65023..79c1db31db3c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java @@ -28,6 +28,7 @@ import com.intellij.execution.configurations.JavaParameters; import com.intellij.execution.configurations.ModuleRunProfile; import com.intellij.execution.configurations.RemoteConnection; import com.intellij.execution.configurations.RunProfileState; +import com.intellij.execution.process.KillableColoredProcessHandler; import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessHandler; @@ -286,7 +287,8 @@ public class DebuggerManagerImpl extends DebuggerManagerEx implements Persistent final DebugProcessImpl debugProcess = getDebugProcess(event.getProcessHandler()); if (debugProcess != null) { // if current thread is a "debugger manager thread", stop will execute synchronously - debugProcess.stop(willBeDestroyed); + // it is KillableColoredProcessHandler responsibility to terminate VM + debugProcess.stop(willBeDestroyed && !(event.getProcessHandler() instanceof KillableColoredProcessHandler)); // wait at most 10 seconds: the problem is that debugProcess.stop() can hang if there are troubles in the debuggee // if processWillTerminate() is called from AWT thread debugProcess.waitFor() will block it and the whole app will hang diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java index 7b76b9738843..02f4ee44fd53 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java @@ -110,7 +110,9 @@ public class JavaEditorTextProviderImpl implements EditorTextProvider { else if (parent instanceof PsiInstanceOfExpression || parent instanceof PsiBinaryExpression || parent instanceof PsiPolyadicExpression - || parent instanceof PsiPrefixExpression) { + || parent instanceof PsiPrefixExpression + || parent instanceof PsiConditionalExpression + ) { if (allowMethodCalls || !DebuggerUtils.hasSideEffects(parent)) { expression = parent; } diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java index e570b642b2bd..a4484cccc1fe 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/CompoundRendererConfigurable.java @@ -25,14 +25,10 @@ import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.ui.DebuggerExpressionTextField; import com.intellij.debugger.ui.JavaDebuggerSupport; import com.intellij.debugger.ui.tree.render.*; -import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.options.UnnamedConfigurable; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; @@ -41,7 +37,7 @@ import com.intellij.ui.table.JBTable; import com.intellij.util.Function; import com.intellij.util.ui.AbstractTableCellEditor; import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.table.AbstractTableModel; @@ -52,57 +48,33 @@ import java.awt.event.*; import java.util.ArrayList; import java.util.List; -/** - * @author Eugene Zhuravlev - * Date: Feb 24, 2005 - */ -public class CompoundRendererConfigurable implements UnnamedConfigurable { +class CompoundRendererConfigurable extends JPanel { private CompoundReferenceRenderer myRenderer; private CompoundReferenceRenderer myOriginalRenderer; private Project myProject; - private ClassNameEditorWithBrowseButton myClassNameField; - private JRadioButton myRbDefaultLabel; - private JRadioButton myRbExpressionLabel; - private JRadioButton myRbDefaultChildrenRenderer; - private JRadioButton myRbExpressionChildrenRenderer; - private JRadioButton myRbListChildrenRenderer; - private DebuggerExpressionTextField myLabelEditor; - private DebuggerExpressionTextField myChildrenEditor; - private DebuggerExpressionTextField myChildrenExpandedEditor; + private final ClassNameEditorWithBrowseButton myClassNameField; + private final JRadioButton myRbDefaultLabel; + private final JRadioButton myRbExpressionLabel; + private final JRadioButton myRbDefaultChildrenRenderer; + private final JRadioButton myRbExpressionChildrenRenderer; + private final JRadioButton myRbListChildrenRenderer; + private final DebuggerExpressionTextField myLabelEditor; + private final DebuggerExpressionTextField myChildrenEditor; + private final DebuggerExpressionTextField myChildrenExpandedEditor; private DebuggerExpressionTextField myListChildrenEditor; - private JComponent myChildrenListEditor; - private JLabel myExpandedLabel; - private JPanel myMainPanel; + private final JLabel myExpandedLabel; private JBTable myTable; @NonNls private static final String EMPTY_PANEL_ID = "EMPTY"; @NonNls private static final String DATA_PANEL_ID = "DATA"; private static final int NAME_TABLE_COLUMN = 0; private static final int EXPRESSION_TABLE_COLUMN = 1; - public CompoundRendererConfigurable(@Nullable Project project) { - myProject = project; - } - - public void setRenderer(NodeRenderer renderer) { - if (renderer instanceof CompoundReferenceRenderer) { - myRenderer = (CompoundReferenceRenderer)renderer; - myOriginalRenderer = (CompoundReferenceRenderer)renderer.clone(); - } - else { - myRenderer = myOriginalRenderer = null; - } - reset(); - } - - public CompoundReferenceRenderer getRenderer() { - return myRenderer; - } + public CompoundRendererConfigurable() { + super(new CardLayout()); - public JComponent createComponent() { if (myProject == null) { myProject = JavaDebuggerSupport.getContextProjectForEditorFieldsInDebuggerConfigurables(); } - final JPanel panel = new JPanel(new GridBagLayout()); myRbDefaultLabel = new JRadioButton(DebuggerBundle.message("label.compound.renderer.configurable.use.default.renderer")); myRbExpressionLabel = new JRadioButton(DebuggerBundle.message("label.compound.renderer.configurable.use.expression")); @@ -121,10 +93,11 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { myLabelEditor = new DebuggerExpressionTextField(myProject, null, "ClassLabelExpression"); myChildrenEditor = new DebuggerExpressionTextField(myProject, null, "ClassChildrenExpression"); myChildrenExpandedEditor = new DebuggerExpressionTextField(myProject, null, "ClassChildrenExpression"); - myChildrenListEditor = createChildrenListEditor(); + JComponent myChildrenListEditor = createChildrenListEditor(); final ItemListener updateListener = new ItemListener() { - public void itemStateChanged(ItemEvent e) { + @Override + public void itemStateChanged(@NotNull ItemEvent e) { updateEnabledState(); } }; @@ -133,7 +106,8 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { myRbExpressionChildrenRenderer.addItemListener(updateListener); myClassNameField = new ClassNameEditorWithBrowseButton(new ActionListener() { - public void actionPerformed(ActionEvent e) { + @Override + public void actionPerformed(@NotNull ActionEvent e) { PsiClass psiClass = DebuggerUtils.getInstance() .chooseClassDialog(DebuggerBundle.message("title.compound.renderer.configurable.choose.renderer.reference.type"), myProject); if (psiClass != null) { @@ -143,20 +117,14 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { } } }, myProject); - final EditorTextField textField = myClassNameField.getEditorTextField(); - final FocusAdapter updateContextListener = new FocusAdapter() { - public void focusLost(FocusEvent e) { - updateContext(myClassNameField.getText()); - } - }; - textField.addFocusListener(updateContextListener); - Disposer.register(myClassNameField, new Disposable() { + myClassNameField.getEditorTextField().addFocusListener(new FocusAdapter() { @Override - public void dispose() { - textField.removeFocusListener(updateContextListener); + public void focusLost(@NotNull FocusEvent e) { + updateContext(myClassNameField.getText()); } }); + JPanel panel = new JPanel(new GridBagLayout()); panel.add(new JLabel(DebuggerBundle.message("label.compound.renderer.configurable.apply.to")), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); @@ -197,15 +165,28 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { panel.add(myChildrenListEditor, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(4, 30, 0, 0), 0, 0)); + add(new JPanel(), EMPTY_PANEL_ID); + add(panel, DATA_PANEL_ID); + } - myMainPanel = new JPanel(new CardLayout()); - myMainPanel.add(new JPanel(), EMPTY_PANEL_ID); - myMainPanel.add(panel, DATA_PANEL_ID); - return myMainPanel; + public void setRenderer(NodeRenderer renderer) { + if (renderer instanceof CompoundReferenceRenderer) { + myRenderer = (CompoundReferenceRenderer)renderer; + myOriginalRenderer = (CompoundReferenceRenderer)renderer.clone(); + } + else { + myRenderer = myOriginalRenderer = null; + } + reset(); + } + + public CompoundReferenceRenderer getRenderer() { + return myRenderer; } private void updateContext(final String qName) { ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override public void run() { final Project project = myProject; final PsiClass psiClass = project != null ? DebuggerUtils.findClass(qName, project, GlobalSearchScope.allScope(project)) : null; @@ -214,6 +195,7 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { myChildrenExpandedEditor.setContext(psiClass); myListChildrenEditor.setContext(psiClass); + assert project != null; PsiType type = DebuggerUtils.getType(qName, project); myLabelEditor.setThisType(type); myChildrenEditor.setThisType(type); @@ -251,17 +233,21 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { final TableColumn exprColumn = myTable.getColumnModel().getColumn(EXPRESSION_TABLE_COLUMN); exprColumn.setCellEditor(new AbstractTableCellEditor() { + @Override public Object getCellEditorValue() { return myListChildrenEditor.getText(); } + @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { myListChildrenEditor.setText((TextWithImports)value); return myListChildrenEditor; } }); exprColumn.setCellRenderer(new DefaultTableCellRenderer() { - public Component getTableCellRendererComponent(JTable table, + @NotNull + @Override + public Component getTableCellRendererComponent(@NotNull JTable table, Object value, boolean isSelected, boolean hasFocus, @@ -309,7 +295,7 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { return !DebuggerUtilsEx.externalizableEqual(cloned, myOriginalRenderer); } - public void apply() throws ConfigurationException { + public void apply() { if (myRenderer == null) { return; } @@ -342,7 +328,7 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { public void reset() { final TextWithImports emptyExpressionFragment = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, ""); - ((CardLayout)myMainPanel.getLayout()).show(myMainPanel, myRenderer == null ? EMPTY_PANEL_ID : DATA_PANEL_ID); + ((CardLayout)getLayout()).show(this, myRenderer == null ? EMPTY_PANEL_ID : DATA_PANEL_ID); if (myRenderer == null) { return; } @@ -390,27 +376,11 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { updateContext(className); } - public void disposeUIResources() { - myRenderer = null; - myOriginalRenderer = null; - myLabelEditor.dispose(); - myChildrenEditor.dispose(); - myChildrenExpandedEditor.dispose(); - myListChildrenEditor.dispose(); - Disposer.dispose(myClassNameField); - myLabelEditor = null; - myChildrenEditor = null; - myChildrenExpandedEditor = null; - myListChildrenEditor = null; - myClassNameField = null; - myProject = null; - } - private MyTableModel getTableModel() { return (MyTableModel)myTable.getModel(); } - private final class MyTableModel extends AbstractTableModel { + private static final class MyTableModel extends AbstractTableModel { private final List<Row> myData = new ArrayList<Row>(); public MyTableModel() { @@ -423,18 +393,23 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { } } + @Override public int getColumnCount() { return 2; } + @Override public int getRowCount() { return myData.size(); } + @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return true; } + @NotNull + @Override public Class getColumnClass(int columnIndex) { switch (columnIndex) { case NAME_TABLE_COLUMN: @@ -446,6 +421,7 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { } } + @Override public Object getValueAt(int rowIndex, int columnIndex) { if (rowIndex >= getRowCount()) { return null; @@ -461,6 +437,7 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { } } + @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if (rowIndex >= getRowCount()) { return; @@ -476,6 +453,8 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { } } + @NotNull + @Override public String getColumnName(int columnIndex) { switch (columnIndex) { case NAME_TABLE_COLUMN: @@ -513,7 +492,7 @@ public class CompoundRendererConfigurable implements UnnamedConfigurable { return pairs; } - private final class Row { + private static final class Row { public String name; public TextWithImports value; diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerLaunchingConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerLaunchingConfigurable.java index 490f99bb5461..b0748cfd336d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerLaunchingConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerLaunchingConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -16,24 +16,23 @@ package com.intellij.debugger.settings; import com.intellij.debugger.DebuggerBundle; -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.options.OptionsBundle; +import com.intellij.openapi.options.ConfigurableUi; import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.StateRestoringCheckBox; import com.intellij.ui.components.panels.VerticalBox; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; -public class DebuggerLaunchingConfigurable implements Configurable { +class DebuggerLaunchingConfigurable implements ConfigurableUi<DebuggerSettings> { private JRadioButton myRbSocket; private JRadioButton myRbShmem; private StateRestoringCheckBox myCbForceClassicVM; private JCheckBox myCbDisableJIT; @Override - public void reset() { - final DebuggerSettings settings = DebuggerSettings.getInstance(); + public void reset(@NotNull DebuggerSettings settings) { if (!SystemInfo.isWindows) { myRbSocket.setSelected(true); myRbShmem.setEnabled(false); @@ -52,8 +51,8 @@ public class DebuggerLaunchingConfigurable implements Configurable { } @Override - public void apply() { - getSettingsTo(DebuggerSettings.getInstance()); + public void apply(@NotNull DebuggerSettings settings) { + getSettingsTo(settings); } private void getSettingsTo(DebuggerSettings settings) { @@ -68,25 +67,15 @@ public class DebuggerLaunchingConfigurable implements Configurable { } @Override - public boolean isModified() { - final DebuggerSettings currentSettings = DebuggerSettings.getInstance(); - final DebuggerSettings debuggerSettings = currentSettings.clone(); + public boolean isModified(@NotNull DebuggerSettings currentSettings) { + DebuggerSettings debuggerSettings = currentSettings.clone(); getSettingsTo(debuggerSettings); return !debuggerSettings.equals(currentSettings); } + @NotNull @Override - public String getDisplayName() { - return OptionsBundle.message("options.java.display.name"); - } - - @Override - public String getHelpTopic() { - return "reference.idesettings.debugger.launching"; - } - - @Override - public JComponent createComponent() { + public JComponent getComponent() { myCbForceClassicVM = new StateRestoringCheckBox(DebuggerBundle.message("label.debugger.launching.configurable.force.classic.vm")); myCbDisableJIT = new JCheckBox(DebuggerBundle.message("label.debugger.launching.configurable.disable.jit")); myRbSocket = new JRadioButton(DebuggerBundle.message("label.debugger.launching.configurable.socket")); @@ -110,12 +99,6 @@ public class DebuggerLaunchingConfigurable implements Configurable { JPanel result = new JPanel(new BorderLayout()); result.add(panel, BorderLayout.NORTH); - return result; } - - - @Override - public void disposeUIResources() { - } }
\ No newline at end of file diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java index cec458ccbb70..cf7e367f1ce8 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -17,10 +17,7 @@ package com.intellij.debugger.settings; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.ui.JavaDebuggerSupport; -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.options.OptionsBundle; -import com.intellij.openapi.options.SearchableConfigurable; -import com.intellij.openapi.project.Project; +import com.intellij.openapi.options.ConfigurableUi; import com.intellij.ui.classFilter.ClassFilterEditor; import org.jetbrains.annotations.NotNull; @@ -29,18 +26,16 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -public class DebuggerSteppingConfigurable implements SearchableConfigurable, Configurable.NoScroll { +class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> { private JCheckBox myCbStepInfoFiltersEnabled; private JCheckBox myCbSkipSyntheticMethods; private JCheckBox myCbSkipConstructors; private JCheckBox myCbSkipClassLoaders; private ClassFilterEditor mySteppingFilterEditor; private JCheckBox myCbSkipSimpleGetters; - private Project myProject; @Override - public void reset() { - final DebuggerSettings settings = DebuggerSettings.getInstance(); + public void reset(@NotNull DebuggerSettings settings) { myCbSkipSimpleGetters.setSelected(settings.SKIP_GETTERS); myCbSkipSyntheticMethods.setSelected(settings.SKIP_SYNTHETIC_METHODS); myCbSkipConstructors.setSelected(settings.SKIP_CONSTRUCTORS); @@ -50,13 +45,11 @@ public class DebuggerSteppingConfigurable implements SearchableConfigurable, Con mySteppingFilterEditor.setFilters(settings.getSteppingFilters()); mySteppingFilterEditor.setEnabled(settings.TRACING_FILTERS_ENABLED); - - } @Override - public void apply() { - getSettingsTo(DebuggerSettings.getInstance()); + public void apply(@NotNull DebuggerSettings settings) { + getSettingsTo(settings); } private void getSettingsTo(DebuggerSettings settings) { @@ -71,39 +64,16 @@ public class DebuggerSteppingConfigurable implements SearchableConfigurable, Con } @Override - public boolean isModified() { - final DebuggerSettings currentSettings = DebuggerSettings.getInstance(); - final DebuggerSettings debuggerSettings = currentSettings.clone(); + public boolean isModified(@NotNull DebuggerSettings currentSettings) { + DebuggerSettings debuggerSettings = currentSettings.clone(); getSettingsTo(debuggerSettings); return !debuggerSettings.equals(currentSettings); } @Override - public String getDisplayName() { - return OptionsBundle.message("options.java.display.name"); - } - - @Override @NotNull - public String getHelpTopic() { - return "reference.idesettings.debugger.stepping"; - } - - @Override - @NotNull - public String getId() { - return getHelpTopic(); - } - - @Override - public Runnable enableSearch(String option) { - return null; - } - - @Override - public JComponent createComponent() { + public JComponent getComponent() { final JPanel panel = new JPanel(new GridBagLayout()); - myProject = JavaDebuggerSupport.getContextProjectForEditorFieldsInDebuggerConfigurables(); myCbSkipSyntheticMethods = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.synthetic.methods")); myCbSkipConstructors = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.constructors")); myCbSkipClassLoaders = new JCheckBox(DebuggerBundle.message("label.debugger.general.configurable.skip.classLoaders")); @@ -115,7 +85,7 @@ public class DebuggerSteppingConfigurable implements SearchableConfigurable, Con panel.add(myCbSkipSimpleGetters, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0),0, 0)); panel.add(myCbStepInfoFiltersEnabled, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(8, 0, 0, 0),0, 0)); - mySteppingFilterEditor = new ClassFilterEditor(myProject, null, "reference.viewBreakpoints.classFilters.newPattern"); + mySteppingFilterEditor = new ClassFilterEditor(JavaDebuggerSupport.getContextProjectForEditorFieldsInDebuggerConfigurables(), null, "reference.viewBreakpoints.classFilters.newPattern"); panel.add(mySteppingFilterEditor, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 5, 0, 0),0, 0)); myCbStepInfoFiltersEnabled.addActionListener(new ActionListener() { @@ -126,11 +96,4 @@ public class DebuggerSteppingConfigurable implements SearchableConfigurable, Con }); return panel; } - - @Override - public void disposeUIResources() { - mySteppingFilterEditor = null; - myProject = null; - } - -} +}
\ No newline at end of file diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/JavaDebuggerSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/JavaDebuggerSettings.java index 7151cb9f650e..e6f271b3981a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/JavaDebuggerSettings.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/JavaDebuggerSettings.java @@ -15,41 +15,78 @@ */ package com.intellij.debugger.settings; +import com.intellij.debugger.DebuggerBundle; import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.OptionsBundle; +import com.intellij.openapi.options.SimpleConfigurable; +import com.intellij.openapi.util.Getter; +import com.intellij.xdebugger.settings.DebuggerSettingsCategory; import com.intellij.xdebugger.settings.XDebuggerSettings; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static java.util.Collections.singletonList; + /** * We cannot now transform DebuggerSettings to XDebuggerSettings: getState/loadState is not called for EP, * but we cannot use standard implementation to save our state, due to backward compatibility we must use own state spec. - * + * <p/> * But we must implement createConfigurable as part of XDebuggerSettings otherwise java general settings will be before xdebugger general setting, * because JavaDebuggerSettingsPanelProvider has higher priority than XDebuggerSettingsPanelProviderImpl. */ -class JavaDebuggerSettings extends XDebuggerSettings<Element> { +public class JavaDebuggerSettings extends XDebuggerSettings<Element> { protected JavaDebuggerSettings() { super("java"); } - @Nullable + @NotNull @Override - public Configurable createConfigurable(@NotNull Category category) { + public Collection<? extends Configurable> createConfigurables(@NotNull DebuggerSettingsCategory category) { + Getter<DebuggerSettings> settingsGetter = new Getter<DebuggerSettings>() { + @Override + public DebuggerSettings get() { + return DebuggerSettings.getInstance(); + } + }; + switch (category) { - case ROOT: - return new DebuggerLaunchingConfigurable(); + case GENERAL: + return singletonList(SimpleConfigurable.create("reference.idesettings.debugger.launching", OptionsBundle.message("options.java.display.name"), + DebuggerLaunchingConfigurable.class, settingsGetter)); case DATA_VIEWS: - return new DebuggerDataViewsConfigurable(null); + return createDataViewsConfigurable(); case STEPPING: - return new DebuggerSteppingConfigurable(); + return singletonList(SimpleConfigurable.create("reference.idesettings.debugger.stepping", OptionsBundle.message("options.java.display.name"), + DebuggerSteppingConfigurable.class, settingsGetter)); + case HOTSWAP: + return singletonList(SimpleConfigurable.create("reference.idesettings.debugger.hotswap", OptionsBundle.message("options.java.display.name"), + JavaHotSwapConfigurableUi.class, settingsGetter)); } - return null; + return Collections.emptyList(); + } + + @SuppressWarnings("SpellCheckingInspection") + @NotNull + public static List<Configurable> createDataViewsConfigurable() { + return Arrays.<Configurable>asList(new DebuggerDataViewsConfigurable(null), + SimpleConfigurable.create("reference.idesettings.debugger.typerenderers", DebuggerBundle.message("user.renderers.configurable.display.name"), + UserRenderersConfigurable.class, new Getter<NodeRendererSettings>() { + @Override + public NodeRendererSettings get() { + return NodeRendererSettings.getInstance(); + } + })); } @Override - public void generalApplied(@NotNull XDebuggerSettings.Category category) { - if (category == XDebuggerSettings.Category.DATA_VIEWS) { + public void generalApplied(@NotNull DebuggerSettingsCategory category) { + if (category == DebuggerSettingsCategory.DATA_VIEWS) { NodeRendererSettings.getInstance().fireRenderersChanged(); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerHotswapConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/JavaHotSwapConfigurableUi.java index a70be30556e2..82a33a895fcb 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerHotswapConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/JavaHotSwapConfigurableUi.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -16,14 +16,14 @@ package com.intellij.debugger.settings; import com.intellij.debugger.DebuggerBundle; -import com.intellij.openapi.options.SearchableConfigurable; +import com.intellij.openapi.options.ConfigurableUi; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.border.Border; import java.awt.*; -public class DebuggerHotswapConfigurable implements SearchableConfigurable { +class JavaHotSwapConfigurableUi implements ConfigurableUi<DebuggerSettings> { private JCheckBox myHotswapInBackground; private JCheckBox myCbCompileBeforeHotswap; private JCheckBox myCbHangWarningEnabled; @@ -31,8 +31,8 @@ public class DebuggerHotswapConfigurable implements SearchableConfigurable { private JRadioButton myRbNever; private JRadioButton myRbAsk; - public void reset() { - final DebuggerSettings settings = DebuggerSettings.getInstance(); + @Override + public void reset(@NotNull DebuggerSettings settings) { myHotswapInBackground.setSelected(settings.HOTSWAP_IN_BACKGROUND); myCbCompileBeforeHotswap.setSelected(settings.COMPILE_BEFORE_HOTSWAP); myCbHangWarningEnabled.setSelected(settings.HOTSWAP_HANG_WARNING_ENABLED); @@ -48,8 +48,9 @@ public class DebuggerHotswapConfigurable implements SearchableConfigurable { } } - public void apply() { - getSettingsTo(DebuggerSettings.getInstance()); + @Override + public void apply(@NotNull DebuggerSettings settings) { + getSettingsTo(settings); } private void getSettingsTo(DebuggerSettings settings) { @@ -68,31 +69,16 @@ public class DebuggerHotswapConfigurable implements SearchableConfigurable { } } - public boolean isModified() { - final DebuggerSettings currentSettings = DebuggerSettings.getInstance(); + @Override + public boolean isModified(@NotNull DebuggerSettings currentSettings) { final DebuggerSettings debuggerSettings = currentSettings.clone(); getSettingsTo(debuggerSettings); return !debuggerSettings.equals(currentSettings); } - public String getDisplayName() { - return DebuggerBundle.message("debugger.hotswap.configurable.display.name"); - } - - public String getHelpTopic() { - return "reference.idesettings.debugger.hotswap"; - } - @NotNull - public String getId() { - return getHelpTopic(); - } - - public Runnable enableSearch(String option) { - return null; - } - - public JComponent createComponent() { + @Override + public JComponent getComponent() { final JPanel panel = new JPanel(new GridBagLayout()); myCbCompileBeforeHotswap = new JCheckBox(DebuggerBundle.message("label.debugger.hotswap.configurable.compile.before.hotswap")); @@ -130,9 +116,4 @@ public class DebuggerHotswapConfigurable implements SearchableConfigurable { return panel; } - - - public void disposeUIResources() { - } - -} +}
\ No newline at end of file diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/UserRenderersConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/UserRenderersConfigurable.java index 3ab2028d5813..3a8505c7dfe8 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/UserRenderersConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/UserRenderersConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -20,17 +20,12 @@ import com.intellij.debugger.ui.tree.render.CompoundNodeRenderer; import com.intellij.debugger.ui.tree.render.NodeRenderer; import com.intellij.ide.util.ElementsChooser; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.options.SearchableConfigurable; -import com.intellij.openapi.project.Project; +import com.intellij.openapi.options.ConfigurableUi; import com.intellij.ui.DocumentAdapter; import com.intellij.util.IconUtil; import com.intellij.util.PlatformIcons; import com.intellij.util.containers.InternalIterator; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.DocumentEvent; @@ -40,56 +35,25 @@ import java.awt.*; import java.util.ArrayList; import java.util.List; -/** - * @author Eugene Zhuravlev - * Date: Feb 19, 2005 - */ -public class UserRenderersConfigurable implements SearchableConfigurable, Configurable.NoScroll { - private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.settings.UserRenderersConfigurable"); +public final class UserRenderersConfigurable extends JPanel implements ConfigurableUi<NodeRendererSettings> { private static final Icon ADD_ICON = IconUtil.getAddIcon(); private static final Icon REMOVE_ICON = IconUtil.getRemoveIcon(); private static final Icon COPY_ICON = PlatformIcons.COPY_ICON; private static final Icon UP_ICON = IconUtil.getMoveUpIcon(); private static final Icon DOWN_ICON = IconUtil.getMoveDownIcon(); - private JPanel myNameFieldPanel; - private JTextField myNameField; + private final JPanel myNameFieldPanel; + private final JTextField myNameField; private ElementsChooser<NodeRenderer> myRendererChooser; private NodeRenderer myCurrentRenderer = null; - private final CompoundRendererConfigurable myRendererDataConfigurable; - - public UserRenderersConfigurable(@Nullable Project project) { - myRendererDataConfigurable = new CompoundRendererConfigurable(project); - } - - public String getDisplayName() { - return DebuggerBundle.message("user.renderers.configurable.display.name"); - } - - public String getHelpTopic() { - return "reference.idesettings.debugger.typerenderers"; - } - - @NotNull - public String getId() { - return getHelpTopic(); - } - - public Runnable enableSearch(String option) { - return null; - } - - public JComponent createComponent() { - final JPanel panel = new JPanel(new BorderLayout(4, 0)); + private final CompoundRendererConfigurable myRendererDataConfigurable = new CompoundRendererConfigurable(); - final JComponent renderersList = createRenderersList(); - final JComponent toolbar = createToolbar(); - final JComponent rendererDataPanel = myRendererDataConfigurable.createComponent(); + public UserRenderersConfigurable() { + super(new BorderLayout(4, 0)); - final JPanel left = new JPanel(new BorderLayout()); - - left.add(toolbar, BorderLayout.NORTH); - left.add(renderersList, BorderLayout.CENTER); + JPanel left = new JPanel(new BorderLayout()); + left.add(createToolbar(), BorderLayout.NORTH); + left.add(createRenderersList(), BorderLayout.CENTER); myNameField = new JTextField(); myNameFieldPanel = new JPanel(new BorderLayout()); @@ -98,11 +62,11 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config myNameFieldPanel.setVisible(false); final JPanel center = new JPanel(new BorderLayout(0, 4)); - center.add(myNameFieldPanel, BorderLayout.NORTH); - center.add(rendererDataPanel, BorderLayout.CENTER); + center.add(myRendererDataConfigurable, BorderLayout.CENTER); myNameField.getDocument().addDocumentListener(new DocumentAdapter() { + @Override protected void textChanged(DocumentEvent e) { if (myCurrentRenderer != null) { myCurrentRenderer.setName(myNameField.getText()); @@ -111,10 +75,14 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config } }); - panel.add(left, BorderLayout.WEST); - panel.add(center, BorderLayout.CENTER); + add(left, BorderLayout.WEST); + add(center, BorderLayout.CENTER); + } - return panel; + @Override + @NotNull + public JComponent getComponent() { + return this; } private JComponent createRenderersList() { @@ -122,12 +90,14 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config myRendererChooser.getEmptyText().setText(DebuggerBundle.message("text.user.renderers.configurable.no.renderers")); myRendererChooser.addElementsMarkListener(new ElementsChooser.ElementsMarkListener<NodeRenderer>() { + @Override public void elementMarkChanged(final NodeRenderer element, final boolean isMarked) { element.setEnabled(isMarked); } }); myRendererChooser.addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent e) { + @Override + public void valueChanged(@NotNull ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { updateCurrentRenderer(myRendererChooser.getSelectedElements()); } @@ -138,7 +108,7 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config private void updateCurrentRenderer(List<NodeRenderer> selectedElements) { if (selectedElements.size() != 1) { - // multiselection + // multi selection setCurrentRenderer(null); } else { @@ -150,13 +120,8 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config if (myCurrentRenderer == renderer) { return; } - try { - if (myRendererDataConfigurable.isModified()) { - myRendererDataConfigurable.apply(); - } - } - catch (ConfigurationException e) { - LOG.error(e); + if (myRendererDataConfigurable.isModified()) { + myRendererDataConfigurable.apply(); } myCurrentRenderer = renderer; if (renderer != null) { @@ -181,11 +146,12 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config return toolbar.getComponent(); } - public void apply() throws ConfigurationException { + @Override + public void apply(@NotNull NodeRendererSettings settings) { myRendererDataConfigurable.apply(); - flushTo(NodeRendererSettings.getInstance().getCustomRenderers()); + flushTo(settings.getCustomRenderers()); - NodeRendererSettings.getInstance().fireRenderersChanged(); + settings.fireRenderersChanged(); } private void flushTo(final RendererConfiguration rendererConfiguration) { @@ -197,11 +163,11 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config rendererConfiguration.setRenderers(renderers); } - public boolean isModified() { + @Override + public boolean isModified(@NotNull NodeRendererSettings settings) { if (myRendererDataConfigurable.isModified()) { return true; } - final NodeRendererSettings settings = NodeRendererSettings.getInstance(); final RendererConfiguration rendererConfiguration = settings.getCustomRenderers(); if (myRendererChooser.getElementCount() != rendererConfiguration.getRendererCount()) { return true; @@ -211,11 +177,13 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config return !uiConfiguration.equals(rendererConfiguration); } - public void reset() { + @Override + public void reset(@NotNull NodeRendererSettings settings) { myRendererChooser.removeAllElements(); - final RendererConfiguration rendererConfiguration = NodeRendererSettings.getInstance().getCustomRenderers(); + final RendererConfiguration rendererConfiguration = settings.getCustomRenderers(); final ArrayList<NodeRenderer> elementsToSelect = new ArrayList<NodeRenderer>(1); rendererConfiguration.iterateRenderers(new InternalIterator<NodeRenderer>() { + @Override public boolean visit(final NodeRenderer renderer) { final NodeRenderer clonedRenderer = (NodeRenderer)renderer.clone(); myRendererChooser.addElement(clonedRenderer, clonedRenderer.isEnabled()); @@ -230,21 +198,18 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config myRendererDataConfigurable.reset(); } - public void disposeUIResources() { - myRendererChooser.removeAllElements(); - myRendererDataConfigurable.disposeUIResources(); - } - private class AddAction extends AnAction { public AddAction() { super(DebuggerBundle.message("button.add"), DebuggerBundle.message("user.renderers.configurable.button.description.add"), ADD_ICON); } + @Override public void actionPerformed(AnActionEvent e) { final NodeRenderer renderer = (NodeRenderer)NodeRendererSettings.getInstance().createRenderer(CompoundNodeRenderer.UNIQUE_ID); renderer.setEnabled(true); myRendererChooser.addElement(renderer, renderer.isEnabled()); SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { myNameField.requestFocus(); } @@ -257,16 +222,18 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config super(DebuggerBundle.message("button.remove"), DebuggerBundle.message("user.renderers.configurable.button.description.remove"), REMOVE_ICON); } + @Override public void actionPerformed(AnActionEvent e) { for (NodeRenderer selectedElement : myRendererChooser.getSelectedElements()) { myRendererChooser.removeElement(selectedElement); } } + @Override public void update(AnActionEvent e) { super.update(e); - final Presentation presentation = e.getPresentation(); - presentation.setEnabled(myRendererChooser.getSelectedElement() != null); + + e.getPresentation().setEnabled(myRendererChooser.getSelectedElement() != null); } } @@ -275,18 +242,18 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config super(DebuggerBundle.message("button.copy"), DebuggerBundle.message("user.renderers.configurable.button.description.copy"), COPY_ICON); } + @Override public void actionPerformed(AnActionEvent e) { final NodeRenderer selectedElement = myRendererChooser.getSelectedElement(); if (selectedElement != null) { - final NodeRenderer cloned = (NodeRenderer)selectedElement.clone(); - myRendererChooser.addElement(cloned, true); + myRendererChooser.addElement((NodeRenderer)selectedElement.clone(), true); } } + @Override public void update(AnActionEvent e) { super.update(e); - final Presentation presentation = e.getPresentation(); - presentation.setEnabled(myRendererChooser.getSelectedElement() != null); + e.getPresentation().setEnabled(myRendererChooser.getSelectedElement() != null); } } @@ -300,6 +267,7 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config myMoveUp = up; } + @Override public void actionPerformed(AnActionEvent e) { final int selectedRow = myRendererChooser.getSelectedElementRow(); if (selectedRow < 0) { @@ -315,10 +283,10 @@ public class UserRenderersConfigurable implements SearchableConfigurable, Config myRendererChooser.moveElement(myRendererChooser.getElementAt(selectedRow), newRow); } + @Override public void update(AnActionEvent e) { super.update(e); - final Presentation presentation = e.getPresentation(); - presentation.setEnabled(myRendererChooser.getSelectedElement() != null); + e.getPresentation().setEnabled(myRendererChooser.getSelectedElement() != null); } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerPanelsManager.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerPanelsManager.java index 3809431c21f8..13336358620b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerPanelsManager.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerPanelsManager.java @@ -214,7 +214,7 @@ public class DebuggerPanelsManager implements ProjectComponent { public void toFront(DebuggerSession session) { DebuggerSessionTab sessionTab = getSessionTab(session); if (sessionTab != null) { - sessionTab.toFront(); + sessionTab.toFront(true); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java index 27f63e032314..20d95f8fff3d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java @@ -18,9 +18,6 @@ package com.intellij.debugger.ui; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.actions.*; import com.intellij.debugger.impl.DebuggerContextImpl; -import com.intellij.debugger.settings.DebuggerHotswapConfigurable; -import com.intellij.debugger.settings.NodeRendererSettings; -import com.intellij.debugger.settings.UserRenderersConfigurable; import com.intellij.debugger.ui.breakpoints.Breakpoint; import com.intellij.ide.DataManager; import com.intellij.openapi.Disposable; @@ -28,7 +25,6 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.markup.GutterIconRenderer; -import com.intellij.openapi.options.Configurable; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.xdebugger.AbstractDebuggerSession; @@ -42,13 +38,11 @@ import com.intellij.xdebugger.impl.actions.MarkObjectActionHandler; import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointItem; import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointPanelProvider; import com.intellij.xdebugger.impl.evaluate.quick.common.QuickEvaluateHandler; -import com.intellij.xdebugger.impl.settings.DebuggerSettingsPanelProvider; import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; -import java.util.ArrayList; import java.util.Collection; /** @@ -68,7 +62,6 @@ public class JavaDebuggerSupport extends DebuggerSupport { private final ShowExecutionPointActionHandler myShowExecutionPointActionHandler = new ShowExecutionPointActionHandler(); //private final EvaluateActionHandler myEvaluateActionHandler = new EvaluateActionHandler(); private final QuickEvaluateActionHandler myQuickEvaluateHandler = new QuickEvaluateActionHandler(); - private final JavaDebuggerSettingsPanelProvider myDebuggerSettingsPanelProvider = new JavaDebuggerSettingsPanelProvider(); private final DebuggerActionHandler mySmartStepIntoHandler = new JvmSmartStepIntoActionHandler(); private final DebuggerActionHandler myAddToWatchedActionHandler = new AddToWatchActionHandler(); private final JavaMarkObjectActionHandler myMarkObjectActionHandler = new JavaMarkObjectActionHandler(); @@ -118,13 +111,13 @@ public class JavaDebuggerSupport extends DebuggerSupport { @Override @NotNull public DebuggerActionHandler getRunToCursorHandler() { - return myRunToCursorActionHandler; + return DISABLED; } @Override @NotNull public DebuggerActionHandler getForceRunToCursorHandler() { - return myForceRunToCursorActionHandler; + return DISABLED; } @Override @@ -216,12 +209,6 @@ public class JavaDebuggerSupport extends DebuggerSupport { return X_EDIT; } - @Override - @NotNull - public DebuggerSettingsPanelProvider getSettingsPanelProvider() { - return myDebuggerSettingsPanelProvider; - } - private static class JavaBreakpointPanelProvider extends BreakpointPanelProvider<Breakpoint> { //private final List<MyBreakpointManagerListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); @@ -335,27 +322,6 @@ public class JavaDebuggerSupport extends DebuggerSupport { //} } - final static class JavaDebuggerSettingsPanelProvider extends DebuggerSettingsPanelProvider { - @Override - public int getPriority() { - return 1; - } - - @NotNull - @Override - public Collection<? extends Configurable> getConfigurables() { - final ArrayList<Configurable> configurables = new ArrayList<Configurable>(); - configurables.add(new UserRenderersConfigurable(null)); - configurables.add(new DebuggerHotswapConfigurable()); - return configurables; - } - - @Override - public void apply() { - NodeRendererSettings.getInstance().fireRenderersChanged(); - } - } - public static Project getContextProjectForEditorFieldsInDebuggerConfigurables() { //todo[nik] improve Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext()); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByPackageRule.java b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByPackageRule.java index f06574569db8..98c772d75044 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByPackageRule.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/XBreakpointGroupingByPackageRule.java @@ -63,6 +63,6 @@ public class XBreakpointGroupingByPackageRule<B> extends XBreakpointGroupingRule @Nullable @Override public Icon getIcon() { - return AllIcons.Nodes.Package; + return AllIcons.Actions.GroupByPackage; } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpoint.java index ebbef2c2ec44..414960b1980a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/AnyExceptionBreakpoint.java @@ -51,7 +51,7 @@ public class AnyExceptionBreakpoint extends ExceptionBreakpoint { public void createRequest(DebugProcessImpl debugProcess) { DebuggerManagerThreadImpl.assertIsManagerThread(); - if (!isEnabled() || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) { + if (!shouldCreateRequest(debugProcess)) { return; } super.processClassPrepare(debugProcess, null); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java index 6879407b3c9a..328dc5f2cd77 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java @@ -33,6 +33,7 @@ import com.intellij.debugger.requests.ClassPrepareRequestor; import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.openapi.util.Key; @@ -46,6 +47,7 @@ import com.intellij.xdebugger.XExpression; import com.intellij.xdebugger.breakpoints.SuspendPolicy; import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.XLineBreakpoint; +import com.intellij.xdebugger.impl.XDebugSessionImpl; import com.intellij.xdebugger.impl.XDebuggerHistoryManager; import com.intellij.xdebugger.impl.XDebuggerUtilImpl; import com.intellij.xdebugger.impl.breakpoints.XBreakpointBase; @@ -95,7 +97,20 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements * Request for creating all needed JPDA requests in the specified VM * @param debuggerProcess the requesting process */ - public abstract void createRequest(DebugProcessImpl debuggerProcess); + public abstract void createRequest(DebugProcessImpl debugProcess); + + protected boolean shouldCreateRequest(final DebugProcessImpl debugProcess) { + return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { + @Override + public Boolean compute() { + JavaDebugProcess process = debugProcess.getXdebugProcess(); + return process != null + && debugProcess.isAttached() + && ((XDebugSessionImpl)process.getSession()).isBreakpointActive(myXBreakpoint) + && debugProcess.getRequestsManager().findRequests(Breakpoint.this).isEmpty(); + } + }); + } /** * Request for creating all needed JPDA requests in the specified VM diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java index d6cbf1487ab9..cc373743736d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java @@ -17,10 +17,7 @@ package com.intellij.debugger.ui.breakpoints; import com.intellij.CommonBundle; import com.intellij.debugger.*; -import com.intellij.debugger.engine.DebugProcess; -import com.intellij.debugger.engine.DebugProcessImpl; -import com.intellij.debugger.engine.DebuggerManagerThreadImpl; -import com.intellij.debugger.engine.JVMNameUtil; +import com.intellij.debugger.engine.*; import com.intellij.debugger.engine.events.DebuggerCommandImpl; import com.intellij.debugger.engine.requests.RequestManagerImpl; import com.intellij.debugger.impl.DebuggerContextImpl; @@ -300,10 +297,7 @@ public abstract class BreakpointWithHighlighter<P extends JavaBreakpointProperti public void createRequest(@NotNull DebugProcessImpl debugProcess) { DebuggerManagerThreadImpl.assertIsManagerThread(); // check is this breakpoint is enabled, vm reference is valid and there're no requests created yet - if (!isEnabled() || - !debugProcess.isAttached() || - isMuted(debugProcess) || - !debugProcess.getRequestsManager().findRequests(this).isEmpty()) { + if (!shouldCreateRequest(debugProcess)) { return; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java index 88ddf4882733..e4f404e909c7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/ExceptionBreakpoint.java @@ -118,7 +118,7 @@ public class ExceptionBreakpoint extends Breakpoint<JavaExceptionBreakpointPrope public void createRequest(final DebugProcessImpl debugProcess) { DebuggerManagerThreadImpl.assertIsManagerThread(); - if (!isEnabled() || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) { + if (!shouldCreateRequest(debugProcess)) { return; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointTypeBase.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointTypeBase.java index a537db14b2e8..4e1d3e2adb3f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointTypeBase.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaBreakpointTypeBase.java @@ -63,7 +63,7 @@ public abstract class JavaBreakpointTypeBase<T extends JavaBreakpointProperties> Breakpoint javaBreakpoint = BreakpointManager.getJavaBreakpoint(breakpoint); if (javaBreakpoint != null) { PsiClass aClass = javaBreakpoint.getPsiClass(); - if (aClass != null && aClass.getContainingFile() != null) { + if (aClass != null && aClass.getContainingFile() != null && aClass.getTextOffset() >= 0) { return XDebuggerUtil.getInstance().createPositionByOffset(aClass.getContainingFile().getVirtualFile(), aClass.getTextOffset()); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/RunToCursorBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/RunToCursorBreakpoint.java index 5b5233a92157..4d43a2b0d557 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/RunToCursorBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/RunToCursorBreakpoint.java @@ -123,4 +123,9 @@ public class RunToCursorBreakpoint extends LineBreakpoint { return new RunToCursorBreakpoint(project, pos, restoreBreakpoints); } + + @Override + protected boolean shouldCreateRequest(DebugProcessImpl debugProcess) { + return debugProcess.isAttached() && debugProcess.getRequestsManager().findRequests(this).isEmpty(); + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/WildcardMethodBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/WildcardMethodBreakpoint.java index c106f65cab81..e8b947c0e865 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/WildcardMethodBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/WildcardMethodBreakpoint.java @@ -129,7 +129,7 @@ public class WildcardMethodBreakpoint extends Breakpoint<JavaMethodBreakpointPro public void createRequest(DebugProcessImpl debugProcess) { DebuggerManagerThreadImpl.assertIsManagerThread(); - if (!isEnabled() || !debugProcess.isAttached() || debugProcess.areBreakpointsMuted() || !debugProcess.getRequestsManager().findRequests(this).isEmpty()) { + if (!shouldCreateRequest(debugProcess)) { return; } try { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java index abda6968def4..f4da39f318a7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java @@ -484,7 +484,7 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements } public boolean canSetValue() { - return !myIsSynthetic && isLvalue(); + return myValueReady && !myIsSynthetic && isLvalue(); } public String getValueLabel() { @@ -534,4 +534,10 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements } } + public boolean canMark() { + if (!myValueReady) { + return false; + } + return getValue() instanceof ObjectReference; + } } diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurable.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurable.java index 04af179638cd..27958a922d2c 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurable.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurable.java @@ -85,7 +85,7 @@ public class ApplicationConfigurable extends SettingsEditor<ApplicationConfigura public void resetEditorFrom(final ApplicationConfiguration configuration) { myCommonProgramParameters.reset(configuration); myModuleSelector.reset(configuration); - getMainClassField().setText(configuration.MAIN_CLASS_NAME.replaceAll("\\$", "\\.")); + getMainClassField().setText(configuration.MAIN_CLASS_NAME != null ? configuration.MAIN_CLASS_NAME.replaceAll("\\$", "\\.") : ""); myAlternativeJREPanel.init(configuration.ALTERNATIVE_JRE_PATH, configuration.ALTERNATIVE_JRE_PATH_ENABLED); updateShowSwingInspector(configuration); diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java index 2370ad3bda71..578d5fbba6ea 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java @@ -21,6 +21,7 @@ import com.intellij.execution.configuration.EnvironmentVariablesComponent; import com.intellij.execution.configurations.*; import com.intellij.execution.filters.TextConsoleBuilderFactory; import com.intellij.execution.junit.RefactoringListeners; +import com.intellij.execution.process.KillableColoredProcessHandler; import com.intellij.execution.process.OSProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.util.JavaParametersUtil; @@ -33,6 +34,7 @@ import com.intellij.openapi.options.SettingsEditorGroup; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; @@ -285,12 +287,17 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration<JavaRunCo @NotNull @Override protected OSProcessHandler startProcess() throws ExecutionException { - final OSProcessHandler handler = super.startProcess(); + OSProcessHandler handler = SystemInfo.isWindows ? super.startProcess() : KillableColoredProcessHandler.create(createCommandLine()); RunnerSettings runnerSettings = getRunnerSettings(); JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(myConfiguration, handler, runnerSettings); return handler; } + @Override + protected boolean ansiColoringEnabled() { + return true; + } + protected ApplicationConfiguration getConfiguration() { return myConfiguration; } diff --git a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java index d472761b017e..3190e19dcee4 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java +++ b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java @@ -224,9 +224,10 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { threadStates = ThreadDumpParser.parse(stdout); if (threadStates == null || threadStates.isEmpty()) { try { + //noinspection BusyWait Thread.sleep(50); } - catch (InterruptedException e1) { + catch (InterruptedException ignored) { // } threadStates = null; diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java b/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java index fbe8636ee360..7627d9396fc5 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/NewProjectWizard.java @@ -46,6 +46,7 @@ public class NewProjectWizard extends AbstractProjectWizard { protected void init(@NotNull ModulesProvider modulesProvider) { myWizardContext.setNewWizard(true); + myWizardContext.setModulesProvider(modulesProvider); ProjectTypeStep projectTypeStep = new ProjectTypeStep(myWizardContext, this, modulesProvider); Disposer.register(getDisposable(), projectTypeStep); mySequence.addCommonStep(projectTypeStep); diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java index 2ed47fd7cb13..8fca04c7aa69 100644 --- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java +++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java @@ -126,6 +126,7 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D private final Map<String, ModuleWizardStep> myCustomSteps = new HashMap<String, ModuleWizardStep>(); private final MultiMap<TemplatesGroup,ProjectTemplate> myTemplatesMap; private String myCurrentCard; + private TemplatesGroup myLastSelectedGroup; public ProjectTypeStep(WizardContext context, NewProjectWizard wizard, ModulesProvider modulesProvider) { myContext = context; @@ -369,7 +370,8 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D // new TemplatesGroup selected public void projectTypeChanged() { TemplatesGroup group = getSelectedGroup(); - if (group == null) return; + if (group == null || group == myLastSelectedGroup) return; + myLastSelectedGroup = group; PropertiesComponent.getInstance().setValue(PROJECT_WIZARD_GROUP, group.getId() ); ModuleBuilder groupModuleBuilder = group.getModuleBuilder(); diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java index 036675179e6f..6c281b0def27 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java @@ -107,6 +107,8 @@ public abstract class FrameworkSupportModelBase extends UserDataHolderBase imple final FrameworkSupportNode node = mySettingsMap.get(providerId); if (node != null && enable != node.isChecked()) { node.setChecked(enable); + // ensure configurable to be created and registered to disposer + node.getConfigurable(); } } diff --git a/java/idea-ui/src/com/intellij/ide/util/projectWizard/NamePathComponent.java b/java/idea-ui/src/com/intellij/ide/util/projectWizard/NamePathComponent.java index d76fa7437167..da18f37c2290 100644 --- a/java/idea-ui/src/com/intellij/ide/util/projectWizard/NamePathComponent.java +++ b/java/idea-ui/src/com/intellij/ide/util/projectWizard/NamePathComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -19,12 +19,12 @@ import com.intellij.ide.IdeBundle; import com.intellij.ide.highlighter.ProjectFileType; import com.intellij.ide.util.BrowseFilesListener; import com.intellij.openapi.application.ApplicationInfo; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.FieldPanel; @@ -138,52 +138,40 @@ public class NamePathComponent extends JPanel{ return component; } - private String getProjectFilePath(boolean isDefault) { - if (isDefault) { - return getPath() + "/" + getNameValue() + ProjectFileType.DOT_DEFAULT_EXTENSION; - } - else { - return getPath() + "/" + Project.DIRECTORY_STORE_FOLDER; - } - } - - public boolean validateNameAndPath(WizardContext context, boolean defaultFormat) throws - ConfigurationException { - final String name = getNameValue(); - if (name.length() == 0) { - final ApplicationInfo info = ApplicationManager.getApplication().getComponent(ApplicationInfo.class); - throw new ConfigurationException( - IdeBundle.message("prompt.new.project.file.name", info.getVersionName(), context.getPresentationName())); + public boolean validateNameAndPath(WizardContext context, boolean defaultFormat) throws ConfigurationException { + String name = getNameValue(); + if (StringUtil.isEmptyOrSpaces(name)) { + ApplicationInfo info = ApplicationInfo.getInstance(); + throw new ConfigurationException(IdeBundle.message("prompt.new.project.file.name", info.getVersionName(), context.getPresentationName())); } - final String projectFileDirectory = getPath(); - if (projectFileDirectory.length() == 0) { + String projectDirectory = getPath(); + if (StringUtil.isEmptyOrSpaces(projectDirectory)) { throw new ConfigurationException(IdeBundle.message("prompt.enter.project.file.location", context.getPresentationName())); } - if (myShouldBeAbsolute && !new File(projectFileDirectory).isAbsolute()) { + if (myShouldBeAbsolute && !new File(projectDirectory).isAbsolute()) { throw new ConfigurationException(StringUtil.capitalize(IdeBundle.message("file.location.should.be.absolute", context.getPresentationName()))); } - final boolean shouldPromptCreation = isPathChangedByUser(); - if (!ProjectWizardUtil - .createDirectoryIfNotExists(IdeBundle.message("directory.project.file.directory", context.getPresentationName()), - projectFileDirectory, shouldPromptCreation)) { + + boolean shouldPromptCreation = isPathChangedByUser(); + String message = IdeBundle.message("directory.project.file.directory", context.getPresentationName()); + if (!ProjectWizardUtil.createDirectoryIfNotExists(message, projectDirectory, shouldPromptCreation)) { return false; } - final File file = new File(projectFileDirectory); + File file = new File(projectDirectory); if (file.exists() && !file.canWrite()) { - throw new ConfigurationException(String.format("Directory '%s' is not writable!\nPlease choose another project location.", projectFileDirectory)); + throw new ConfigurationException(String.format("Directory '%s' is not writable!\nPlease choose another project location.", projectDirectory)); } boolean shouldContinue = true; - final File projectFile = new File(getProjectFilePath(defaultFormat)); + String fileName = defaultFormat ? name + ProjectFileType.DOT_DEFAULT_EXTENSION : Project.DIRECTORY_STORE_FOLDER; + File projectFile = new File(file, fileName); if (projectFile.exists()) { - int answer = Messages.showYesNoDialog( - IdeBundle.message("prompt.overwrite.project.file", projectFile.getAbsolutePath(), context.getPresentationName()), - IdeBundle.message("title.file.already.exists"), Messages.getQuestionIcon()); + message = IdeBundle.message("prompt.overwrite.project.file", projectFile.getAbsolutePath(), context.getPresentationName()); + int answer = Messages.showYesNoDialog(message, IdeBundle.message("title.file.already.exists"), Messages.getQuestionIcon()); shouldContinue = (answer == Messages.YES); } - return shouldContinue; } @@ -204,14 +192,15 @@ public class NamePathComponent extends JPanel{ } public String getPath() { - return myTfPath.getText().trim().replace(File.separatorChar, '/'); + String text = myTfPath.getText().trim(); + return FileUtil.expandUserHome(FileUtil.toSystemIndependentName(text)); } public void setPath(String path) { final boolean isPathChangedByUser = myIsPathChangedByUser; setPathNameSyncEnabled(false); try { - myTfPath.setText(path); + myTfPath.setText(FileUtil.getLocationRelativeToUserHome(FileUtil.toSystemDependentName(path))); } finally { myIsPathChangedByUser = isPathChangedByUser; diff --git a/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/SdkEditor.java b/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/SdkEditor.java index 68e174159e1a..0c41048c0db8 100644 --- a/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/SdkEditor.java +++ b/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/SdkEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -32,6 +32,7 @@ import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.TabbedPaneWrapper; import com.intellij.ui.navigation.History; @@ -151,11 +152,13 @@ public class SdkEditor implements Configurable, Place.Navigator { myHomeComponent.getTextField().setEditable(false); myHomeFieldLabel = new JLabel(getHomeFieldLabelValue()); - myMainPanel.add(myHomeFieldLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(2, 0, 2, 2), 0, 0)); - myMainPanel.add(myHomeComponent, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, 0), 0, 0)); + final int leftInset = Registry.is("ide.new.project.settings") ? 10 : 0; + final int rightInset = Registry.is("ide.new.project.settings") ? 10 : 0; + myMainPanel.add(myHomeFieldLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(2, leftInset, 2, 2), 0, 0)); + myMainPanel.add(myHomeComponent, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, rightInset), 0, 0)); myAdditionalDataPanel = new JPanel(new BorderLayout()); - myMainPanel.add(myAdditionalDataPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 0), 0, 0)); + myMainPanel.add(myAdditionalDataPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, leftInset, 0, rightInset), 0, 0)); myMainPanel.add(myTabbedPane.getComponent(), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 0), 0, 0)); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntriesEditor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntriesEditor.java index cbfd826d8462..73f9f7f39807 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntriesEditor.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaContentEntriesEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -26,6 +26,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -140,6 +141,7 @@ public class JavaContentEntriesEditor extends CommonContentEntriesEditor { @Override protected JPanel createBottomControl(Module module) { + if (Registry.is("ide.new.project.settings")) return null; final JPanel innerPanel = new JPanel(new GridBagLayout()); innerPanel.setBorder(BorderFactory.createEmptyBorder(6, 0, 0, 6)); return innerPanel; diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.form b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.form index 292c1f6c81c6..576d5146ff89 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.form +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.form @@ -1,12 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.openapi.roots.ui.configuration.ProjectConfigurable"> <grid id="27dc6" binding="myWholePanel" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="10"> - <margin top="14" left="4" bottom="4" right="4"/> + <margin top="0" left="0" bottom="0" right="0"/> <constraints> - <xy x="20" y="20" width="907" height="282"/> + <xy x="20" y="20" width="907" height="288"/> </constraints> <properties/> - <border type="none"/> + <border type="none"> + <size top="14" left="10" bottom="14" right="10"/> + </border> <children> <vspacer id="2fb9d"> <constraints> diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java index 9c46d56ce21e..2bc8499e6c01 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -39,6 +39,7 @@ import com.intellij.openapi.ui.DetailsComponent; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.pom.java.LanguageLevel; @@ -49,6 +50,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import java.awt.*; import java.io.IOException; @@ -108,7 +110,7 @@ public class ProjectConfigurable extends ProjectStructureElementConfigurable<Pro @Override public JComponent createOptionsPanel() { - myDetailsComponent = new DetailsComponent(); + myDetailsComponent = new DetailsComponent(!Registry.is("ide.new.project.settings"), !Registry.is("ide.new.project.settings")); myDetailsComponent.setContent(myPanel); myDetailsComponent.setText(getBannerSlogan()); @@ -152,7 +154,7 @@ public class ProjectConfigurable extends ProjectStructureElementConfigurable<Pro myPanel.add(myWholePanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0)); - + myPanel.setBorder(new EmptyBorder(0, 10, 0, 10)); myProjectCompilerOutput.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java index d78731b0a3c8..f24153739031 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectJdksConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -161,6 +161,9 @@ public class ProjectJdksConfigurable extends MasterDetailsComponent { @Override @Nullable protected ArrayList<AnAction> createActions(final boolean fromPopup) { + if (myProjectJdksModel == null) { + return null; + } final ArrayList<AnAction> actions = new ArrayList<AnAction>(); DefaultActionGroup group = new DefaultActionGroup(ProjectBundle.message("add.new.jdk.text"), true); group.getTemplatePresentation().setIcon(IconUtil.getAddIcon()); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java index bf083f92c66c..a5867d66d176 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java @@ -44,6 +44,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy; import com.intellij.packaging.artifacts.Artifact; import com.intellij.ui.JBSplitter; +import com.intellij.ui.OnePixelSplitter; import com.intellij.ui.components.panels.Wrapper; import com.intellij.ui.navigation.BackAction; import com.intellij.ui.navigation.ForwardAction; @@ -174,12 +175,9 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se public JComponent createComponent() { myComponent = new MyPanel(); - mySplitter = new JBSplitter(false, .15f); + mySplitter = Registry.is("ide.new.project.settings") ? new OnePixelSplitter(false, .15f) : new JBSplitter(false, .15f); mySplitter.setSplitterProportionKey("ProjectStructure.TopLevelElements"); mySplitter.setHonorComponentsMinimumSize(true); - if (Registry.is("ide.new.project.settings")) { - mySplitter.setOnePixelMode(); - } initSidePanel(); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/SidePanel.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/SidePanel.java index 290f35e561b5..355888b02a42 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/SidePanel.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/SidePanel.java @@ -20,7 +20,10 @@ import com.intellij.openapi.ui.GraphicsConfig; import com.intellij.openapi.ui.popup.ListItemDescriptor; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.*; +import com.intellij.ui.Gray; +import com.intellij.ui.JBColor; +import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.SeparatorWithText; import com.intellij.ui.components.JBList; import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.ui.navigation.History; @@ -172,16 +175,14 @@ public class SidePanel extends JPanel { protected JComponent createItemComponent() { myExtraPanel = new NonOpaquePanel(new BorderLayout()); myCountLabel = new CountLabel(); - + final JComponent component = super.createItemComponent(); if (Registry.is("ide.new.project.settings")) { - myTextLabel = new EngravedLabel(); - myTextLabel.setFont(myTextLabel.getFont().deriveFont(Font.BOLD)); myTextLabel.setForeground(Gray._240); myTextLabel.setOpaque(true); - return layoutComponent(myTextLabel); } - return super.createItemComponent(); + + return component; } @Override diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java index 69b490828f0b..618f085f00bb 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -34,12 +34,12 @@ import com.intellij.openapi.roots.ui.configuration.artifacts.sourceItems.Library import com.intellij.openapi.roots.ui.configuration.artifacts.sourceItems.ModuleOutputSourceItem; import com.intellij.openapi.roots.ui.configuration.artifacts.sourceItems.SourceItemsTree; import com.intellij.openapi.ui.FixedSizeButton; -import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtilRt; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.packaging.artifacts.Artifact; @@ -83,6 +83,7 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { private JPanel myErrorPanelPlace; private ThreeStateCheckBox myShowContentCheckBox; private FixedSizeButton myShowSpecificContentOptionsButton; + private JPanel myTopPanel; private final ActionGroup myShowSpecificContentOptionsGroup; private final Project myProject; private final ComplexElementSubstitutionParameters mySubstitutionParameters = new ComplexElementSubstitutionParameters(); @@ -106,6 +107,9 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { myPropertiesEditors = new ArtifactPropertiesEditors(myContext, myOriginalArtifact, myOriginalArtifact); Disposer.register(this, mySourceItemsTree); Disposer.register(this, myLayoutTreeComponent); + if (Registry.is("ide.new.project.settings")) { + myTopPanel.setBorder(new EmptyBorder(0, 10, 0, 10)); + } myBuildOnMakeCheckBox.setSelected(artifact.isBuildOnMake()); final String outputPath = artifact.getOutputPath(); myOutputDirectoryField.addBrowseFolderListener(CompilerBundle.message("dialog.title.output.directory.for.artifact"), @@ -202,7 +206,7 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { myErrorPanelPlace.add(myValidationManager.getMainErrorPanel(), BorderLayout.CENTER); - Splitter splitter = new Splitter(false); + final JBSplitter splitter = Registry.is("ide.new.project.settings") ? new OnePixelSplitter(false) : new JBSplitter(false); final JPanel leftPanel = new JPanel(new BorderLayout()); JPanel treePanel = myLayoutTreeComponent.getTreePanel(); if (UIUtil.isUnderDarcula()) { @@ -213,7 +217,7 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { leftPanel.add(treePanel, BorderLayout.CENTER); if (UIUtil.isUnderDarcula()) { CompoundBorder border = - new CompoundBorder(new CustomLineBorder(UIUtil.getBorderColor(), 0, 0, 0, 1), BorderFactory.createEmptyBorder(0, 0, 0, 0)); + new CompoundBorder(new CustomLineBorder(0, 0, 0, 1), BorderFactory.createEmptyBorder(0, 0, 0, 0)); leftPanel.setBorder(border); } else { leftPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 0)); @@ -241,7 +245,7 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { labelPanel.add(link); rightTopPanel.add(labelPanel, BorderLayout.CENTER); rightPanel.add(rightTopPanel, BorderLayout.NORTH); - JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(mySourceItemsTree, UIUtil.isUnderDarcula()); + JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(mySourceItemsTree, UIUtil.isUnderDarcula() || Registry.is("ide.new.project.settings")); JPanel scrollPaneWrap = new JPanel(new BorderLayout()); scrollPaneWrap.add(scrollPane, BorderLayout.CENTER); if (UIUtil.isUnderDarcula()) { @@ -257,6 +261,13 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { rightPanel.setBorder(BorderFactory.createEmptyBorder(3, 0, 3, 3)); } splitter.setSecondComponent(rightPanel); + if (Registry.is("ide.new.project.settings")) { + splitter.getDivider().setBackground(UIUtil.getPanelBackground()); + treePanel.setBorder(new EmptyBorder(0, 0, 0, 0)); + rightPanel.setBorder(new EmptyBorder(0, 0, 0, 0)); + scrollPaneWrap.setBorder(new EmptyBorder(0,0,0,0)); + leftPanel.setBorder(new EmptyBorder(0,0,0,0)); + } myShowContentCheckBox.addActionListener(new ActionListener() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsEditorImpl.form b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsEditorImpl.form index d3edac73dcf3..17c98953e52a 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsEditorImpl.form +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsEditorImpl.form @@ -8,7 +8,7 @@ <properties/> <border type="none"/> <children> - <grid id="6e544" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <grid id="6e544" binding="myTopPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java index 52b601e4d9fe..5deea9c75f74 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactsStructureConfigurable.java @@ -286,25 +286,7 @@ public class ArtifactsStructureConfigurable extends BaseStructureConfigurable { } private void addArtifact(@NotNull ArtifactType type, @NotNull ArtifactTemplate artifactTemplate) { - final ArtifactTemplate.NewArtifactConfiguration configuration = artifactTemplate.createArtifact(); - if (configuration == null) { - return; - } - - final String baseName = configuration.getArtifactName(); - String name = baseName; - int i = 2; - while (myPackagingEditorContext.getArtifactModel().findArtifact(name) != null) { - name = baseName + i; - i++; - } - - ArtifactType actualType = configuration.getArtifactType(); - if (actualType == null) { - actualType = type; - } - final ModifiableArtifact artifact = myPackagingEditorContext.getOrCreateModifiableArtifactModel().addArtifact(name, actualType, configuration.getRootElement()); - artifactTemplate.setUpArtifact(artifact, configuration); + Artifact artifact = ArtifactUtil.addArtifact(myPackagingEditorContext.getOrCreateModifiableArtifactModel(), type, artifactTemplate); selectNodeInTree(findNodeByObject(myRoot, artifact)); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTreeComponent.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTreeComponent.java index ff1fdd393961..d8392ea73e63 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTreeComponent.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/LayoutTreeComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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,7 +47,6 @@ import com.intellij.ui.treeStructure.SimpleTreeStructure; import com.intellij.ui.treeStructure.WeightBasedComparator; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -132,7 +131,7 @@ public class LayoutTreeComponent implements DnDTarget, Disposable { emptyPanel.setPreferredSize(new Dimension(0, 0)); myPropertiesPanelWrapper = new JPanel(new CardLayout()); - myPropertiesPanel.setBorder(new CustomLineBorder(UIUtil.getBorderColor(), 1, 0, 0, 0)); + myPropertiesPanel.setBorder(new CustomLineBorder(1, 0, 0, 0)); myPropertiesPanelWrapper.add(EMPTY_CARD, emptyPanel); myPropertiesPanelWrapper.add(PROPERTIES_CARD, myPropertiesPanel); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/LibraryRootsComponent.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/LibraryRootsComponent.java index 5d884a6f9bc8..e47e955fff24 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/LibraryRootsComponent.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/LibraryRootsComponent.java @@ -41,6 +41,7 @@ import com.intellij.openapi.ui.ex.MultiLineLabel; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -48,6 +49,7 @@ import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.ui.AnActionButton; import com.intellij.ui.AnActionButtonRunnable; import com.intellij.ui.ToolbarDecorator; +import com.intellij.ui.border.CustomLineBorder; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.ArrayUtil; import com.intellij.util.IconUtil; @@ -157,7 +159,9 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myTree).disableUpDownActions() .setRemoveActionName(ProjectBundle.message("library.remove.action")) .disableRemoveAction(); - + if (Registry.is("ide.new.project.settings")) { + toolbarDecorator.setPanelBorder(new CustomLineBorder(1, 0, 0, 0)); + } final List<AttachRootButtonDescriptor> popupItems = new ArrayList<AttachRootButtonDescriptor>(); for (AttachRootButtonDescriptor descriptor : myDescriptor.createAttachButtons()) { Icon icon = descriptor.getToolbarIcon(); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java index b88f92474fcf..a3b1db0dcf24 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/BaseStructureConfigurable.java @@ -38,7 +38,6 @@ import com.intellij.openapi.ui.NamedConfigurable; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; import com.intellij.packaging.artifacts.Artifact; import com.intellij.ui.TreeSpeedSearch; @@ -302,7 +301,7 @@ public abstract class BaseStructureConfigurable extends MasterDetailsComponent i result.addAll(copyActions); result.add(Separator.getInstance()); - if (fromPopup || !(SystemInfo.isMac && Registry.is("ide.new.project.settings"))) { + if (fromPopup || !Registry.is("ide.new.project.settings")) { result.add(new MyFindUsagesAction(myTree)); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FacetStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FacetStructureConfigurable.java index e5a008d3dcbb..d5248a55e7ad 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FacetStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FacetStructureConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -35,6 +35,7 @@ import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.FacetProje import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; import com.intellij.openapi.ui.DetailsComponent; import com.intellij.openapi.ui.NamedConfigurable; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.treeStructure.filtered.FilteringTreeBuilder; import com.intellij.util.ui.tree.TreeUtil; @@ -277,8 +278,10 @@ public class FacetStructureConfigurable extends BaseStructureConfigurable { actions.add(new MyNavigateAction()); } actions.add(new MyRemoveAction()); - actions.add(Separator.getInstance()); - addCollapseExpandActions(actions); + if (fromPopup || !(Registry.is("ide.new.project.settings"))) { + actions.add(Separator.getInstance()); + addCollapseExpandActions(actions); + } return actions; } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FacetsTreeCellRenderer.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FacetsTreeCellRenderer.java index d89fe3797478..216ad982bbd3 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FacetsTreeCellRenderer.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/FacetsTreeCellRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -54,15 +54,7 @@ public class FacetsTreeCellRenderer extends GroupedElementsRenderer.Tree { if (configurable != null) { final Icon icon = configurable.getIcon(expanded); final boolean showSeparator = configurable instanceof FrameworkDetectionConfigurable; - int width = -1; - if (showSeparator && tree.isVisible()) { - final int treeWidth = tree.getVisibleRect().width; - if (treeWidth > 0) { - width = treeWidth; - } - } - final JComponent component = configureComponent(node.getDisplayName(), null, icon, icon, selected, showSeparator, null, - width); + final JComponent component = configureComponent(node.getDisplayName(), null, icon, icon, selected, showSeparator, null, -1); myTextLabel.setOpaque(selected); return component; diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java index 1c313c1077ee..a2a7e6b5c76f 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java @@ -53,7 +53,6 @@ import com.intellij.openapi.ui.*; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.NullableComputable; -import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; @@ -149,9 +148,9 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple @NotNull protected ArrayList<AnAction> createActions(final boolean fromPopup) { final ArrayList<AnAction> result = super.createActions(fromPopup); - result.add(Separator.getInstance()); - result.add(new MyGroupAction()); - if (fromPopup || !(SystemInfo.isMac && Registry.is("ide.new.project.settings"))) { + if (fromPopup || !Registry.is("ide.new.project.settings")) { + result.add(Separator.getInstance()); + result.add(new MyGroupAction()); addCollapseExpandActions(result); } return result; diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index 7f8d01382b09..c23ebdd00855 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -1292,5 +1292,31 @@ public class GenericsHighlightUtil { } } } + + public static HighlightInfo checkInferredIntersections(PsiSubstitutor substitutor, TextRange ref) { + for (Map.Entry<PsiTypeParameter, PsiType> typeEntry : substitutor.getSubstitutionMap().entrySet()) { + final PsiType type = typeEntry.getValue(); + if (type instanceof PsiIntersectionType) { + final PsiType[] conjuncts = ((PsiIntersectionType)type).getConjuncts(); + for (int i = 0; i < conjuncts.length; i++) { + PsiClass conjunct = PsiUtil.resolveClassInClassTypeOnly(conjuncts[i]); + if (conjunct != null && !conjunct.isInterface()) { + for (int i1 = i + 1; i1 < conjuncts.length; i1++) { + PsiClass oppositeConjunct = PsiUtil.resolveClassInClassTypeOnly(conjuncts[i1]); + if (oppositeConjunct != null && !oppositeConjunct.isInterface()) { + if (!conjunct.isInheritor(oppositeConjunct, true) && !oppositeConjunct.isInheritor(conjunct, true)) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .descriptionAndTooltip("Type parameter " + typeEntry.getKey().getName() + " has incompatible upper bounds: " + + conjunct.getName() + " and " + oppositeConjunct.getName()) + .range(ref).create(); + } + } + } + } + } + } + } + return null; + } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java index 602e3fea2cc2..a4ea7087af5a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java @@ -696,14 +696,17 @@ public class HighlightControlFlowUtil { return true; } - if (ControlFlowUtil.isVariableDefinitelyAssigned(variable, controlFlow)) { - final Collection<ControlFlowUtil.VariableInfo> initializedTwice = ControlFlowUtil.getInitializedTwice(controlFlow); - effectivelyFinal = !initializedTwice.contains(new ControlFlowUtil.VariableInfo(variable, null)); - if (effectivelyFinal) { - effectivelyFinal = notAccessedForWriting(variable, new LocalSearchScope(scope)); + final List<PsiReferenceExpression> readBeforeWriteLocals = ControlFlowUtil.getReadBeforeWriteLocals(controlFlow); + for (PsiReferenceExpression expression : readBeforeWriteLocals) { + if (expression.resolve() == variable) { + return PsiUtil.isAccessedForReading(expression); } - } else { - effectivelyFinal = false; + } + + final Collection<ControlFlowUtil.VariableInfo> initializedTwice = ControlFlowUtil.getInitializedTwice(controlFlow); + effectivelyFinal = !initializedTwice.contains(new ControlFlowUtil.VariableInfo(variable, null)); + if (effectivelyFinal) { + effectivelyFinal = notAccessedForWriting(variable, new LocalSearchScope(scope)); } } return effectivelyFinal; diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index b567ce41325a..118c98efc9d2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -344,8 +344,12 @@ public class HighlightMethodUtil { if (resolved instanceof PsiMethod && resolveResult.isValidResult()) { TextRange fixRange = getFixRange(methodCall); highlightInfo = HighlightUtil.checkUnhandledExceptions(methodCall, fixRange); - if (highlightInfo == null && !LambdaUtil.isValidQualifier4InterfaceStaticMethodCall((PsiMethod)resolved, methodCall.getMethodExpression(), resolveResult.getCurrentFileResolveScope(), languageLevel)) { - highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip("Static method may be invoked on containing interface class only").range(fixRange).create(); + if (highlightInfo == null) { + if (!LambdaUtil.isValidQualifier4InterfaceStaticMethodCall((PsiMethod)resolved, methodCall.getMethodExpression(), resolveResult.getCurrentFileResolveScope(), languageLevel)) { + highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip("Static method may be invoked on containing interface class only").range(fixRange).create(); + } else { + highlightInfo = GenericsHighlightUtil.checkInferredIntersections(substitutor, fixRange); + } } } else { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java index c1f127d3a1df..621ce3fce2af 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java @@ -141,7 +141,19 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection .inferTypeArguments(method.getTypeParameters(), parameters, expressions, ((MethodCandidateInfo)result).getSiteSubstitutor(), callExpr.getParent(), DefaultParameterTypeInferencePolicy.INSTANCE); - return substitutor.substitute(parameters[i].getType()); + PsiType paramType; + if (i < parameters.length) { + paramType = parameters[i].getType(); + } + else { + paramType = parameters[parameters.length - 1].getType(); + if (!(paramType instanceof PsiEllipsisType)) { + return null; + } + paramType = ((PsiEllipsisType)paramType).getComponentType(); + } + + return substitutor.substitute(paramType); } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java index 44e493c63f0a..47ef448c7484 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java @@ -208,7 +208,8 @@ class MakeResult<Res> implements PendingAction<Res> { } abstract class Analysis<Res> { - private static final int STEPS_LIMIT = 30000; + public static final int STEPS_LIMIT = 30000; + public static final int EQUATION_SIZE_LIMIT = 30; final RichControlFlow richControlFlow; final Direction direction; final ControlFlowGraph controlFlow; @@ -225,7 +226,7 @@ abstract class Analysis<Res> { Res earlyResult = null; abstract Res identity(); - abstract Res combineResults(Res delta, List<Res> subResults); + abstract Res combineResults(Res delta, List<Res> subResults) throws AnalyzerException; abstract boolean isEarlyResult(Res res); abstract Equation<Key, Value> mkEquation(Res result); abstract void processState(State state) throws AnalyzerException; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java index f29dd7f6cf0c..0239a661c4ee 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java @@ -15,112 +15,68 @@ */ package com.intellij.codeInspection.bytecodeAnalysis; -import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.io.*; -import gnu.trove.TIntHashSet; -import gnu.trove.TIntObjectHashMap; -import gnu.trove.TIntObjectIterator; +import gnu.trove.TLongArrayList; +import gnu.trove.TLongHashSet; +import gnu.trove.TLongObjectHashMap; +import gnu.trove.TLongObjectIterator; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.org.objectweb.asm.Type; -import java.io.DataInput; -import java.io.DataOutput; -import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; import static com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalysis.LOG; /** * @author lambdamix */ -public class BytecodeAnalysisConverter implements ApplicationComponent { +public abstract class BytecodeAnalysisConverter implements ApplicationComponent { - private static final String VERSION = "BytecodeAnalysisConverter.Enumerators"; + public static final int SHIFT = 4096; public static BytecodeAnalysisConverter getInstance() { return ApplicationManager.getApplication().getComponent(BytecodeAnalysisConverter.class); } - private PersistentStringEnumerator myNamesEnumerator; - private PersistentEnumeratorDelegate<int[]> myCompoundKeyEnumerator; - private int version; - - @Override - public void initComponent() { - version = PropertiesComponent.getInstance().getOrInitInt(VERSION, 0); - final File keysDir = new File(PathManager.getIndexRoot(), "bytecodekeys"); - final File namesFile = new File(keysDir, "names"); - final File compoundKeysFile = new File(keysDir, "compound"); - - try { - IOUtil.openCleanOrResetBroken(new ThrowableComputable<Void, IOException>() { - @Override - public Void compute() throws IOException { - myNamesEnumerator = new PersistentStringEnumerator(namesFile, true); - myCompoundKeyEnumerator = new IntArrayPersistentEnumerator(compoundKeysFile, new IntArrayKeyDescriptor()); - return null; - } - }, new Runnable() { - @Override - public void run() { - LOG.info("Error during initialization of enumerators in bytecode analysis. Re-initializing."); - IOUtil.deleteAllFilesStartingWith(keysDir); - version ++; - } - }); - } - catch (IOException e) { - LOG.error("Re-initialization of enumerators in bytecode analysis failed.", e); - } - // TODO: is it enough for rebuilding indices? - PropertiesComponent.getInstance().setValue(VERSION, String.valueOf(version)); - } - - @Override - public void disposeComponent() { - try { - myNamesEnumerator.close(); - myCompoundKeyEnumerator.close(); - } - catch (IOException e) { - LOG.debug(e); - } - } - @NotNull @Override public String getComponentName() { return "BytecodeAnalysisConverter"; } - IntIdEquation convert(Equation<Key, Value> equation) throws IOException { + public abstract int getVersion(); + + protected abstract int enumerateString(@NotNull String s) throws IOException; + + protected abstract int enumerateCompoundKey(@NotNull int[] key) throws IOException; + + IdEquation convert(Equation<Key, Value> equation) throws IOException { ProgressManager.checkCanceled(); Result<Key, Value> rhs = equation.rhs; - IntIdResult result; + IdResult result; if (rhs instanceof Final) { - result = new IntIdFinal(((Final<Key, Value>)rhs).value); + result = new IdFinal(((Final<Key, Value>)rhs).value); } else { Pending<Key, Value> pending = (Pending<Key, Value>)rhs; Set<Product<Key, Value>> sumOrigin = pending.sum; IntIdComponent[] components = new IntIdComponent[sumOrigin.size()]; int componentI = 0; for (Product<Key, Value> prod : sumOrigin) { - int[] intProd = new int[prod.ids.size()]; + long[] intProd = new long[prod.ids.size()]; int idI = 0; for (Key id : prod.ids) { - int rawId = mkAsmKey(id); + long rawId = mkAsmKey(id); if (rawId <= 0) { LOG.error("raw key should be positive. rawId = " + rawId); } @@ -131,24 +87,51 @@ public class BytecodeAnalysisConverter implements ApplicationComponent { components[componentI] = intIdComponent; componentI++; } - result = new IntIdPending(components); + result = new IdPending(components); } - int rawKey = mkAsmKey(equation.id); + long rawKey = mkAsmKey(equation.id); if (rawKey <= 0) { LOG.error("raw key should be positive. rawKey = " + rawKey); } - int key = equation.id.stable ? rawKey : -rawKey; - return new IntIdEquation(key, result); + long key = equation.id.stable ? rawKey : -rawKey; + return new IdEquation(key, result); } - public int mkAsmKey(@NotNull Key key) throws IOException { - return myCompoundKeyEnumerator.enumerate(new int[]{mkDirectionKey(key.direction), mkAsmSignatureKey(key.method)}); + public long mkAsmKey(@NotNull Key key) throws IOException { + long baseKey = mkAsmSignatureKey(key.method); + long directionKey = mkDirectionKey(key.direction); + return baseKey * SHIFT + directionKey; } - private int mkDirectionKey(Direction dir) throws IOException { - return myCompoundKeyEnumerator.enumerate(new int[]{dir.directionId(), dir.paramId(), dir.valueId()}); + private static int mkDirectionKey(Direction dir) throws IOException { + if (dir instanceof Out) { + return 0; + } else if (dir instanceof In) { + In in = (In)dir; + return 8 * in.paramId() + 1; + } else { + InOut inOut = (InOut)dir; + return 8 * inOut.paramId() + 2 + inOut.valueId(); + } + } + + @NotNull + private static Direction extractDirection(int directionKey) { + if (directionKey == 0) { + return new Out(); + } + else { + int paramId = directionKey / 8; + int subDirection = directionKey % 8; + if (subDirection == 1) { + return new In(paramId); + } + else { + return new InOut(paramId, Value.values()[subDirection - 2]); + } + } } // class + short signature @@ -156,33 +139,19 @@ public class BytecodeAnalysisConverter implements ApplicationComponent { int[] sigKey = new int[2]; sigKey[0] = mkAsmTypeKey(Type.getObjectType(method.internalClassName)); sigKey[1] = mkAsmShortSignatureKey(method); - return myCompoundKeyEnumerator.enumerate(sigKey); + return enumerateCompoundKey(sigKey); } private int mkAsmShortSignatureKey(@NotNull Method method) throws IOException { Type[] argTypes = Type.getArgumentTypes(method.methodDesc); int arity = argTypes.length; - int[] sigKey = new int[3 + arity]; + int[] sigKey = new int[2 + arity]; sigKey[0] = mkAsmTypeKey(Type.getReturnType(method.methodDesc)); - sigKey[1] = myNamesEnumerator.enumerate(method.methodName); - sigKey[2] = argTypes.length; + sigKey[1] = enumerateString(method.methodName); for (int i = 0; i < argTypes.length; i++) { - sigKey[3 + i] = mkAsmTypeKey(argTypes[i]); + sigKey[2 + i] = mkAsmTypeKey(argTypes[i]); } - return myCompoundKeyEnumerator.enumerate(sigKey); - } - - @Nullable - private static Direction extractDirection(int[] directionKey) { - switch (directionKey[0]) { - case Direction.OUT_DIRECTION: - return new Out(); - case Direction.IN_DIRECTION: - return new In(directionKey[1]); - case Direction.INOUT_DIRECTION: - return new InOut(directionKey[1], Value.values()[directionKey[2]]); - } - return null; + return enumerateCompoundKey(sigKey); } private int mkAsmTypeKey(Type type) throws IOException { @@ -197,22 +166,22 @@ public class BytecodeAnalysisConverter implements ApplicationComponent { packageName = ""; simpleName = className; } - int[] classKey = new int[]{myNamesEnumerator.enumerate(packageName), myNamesEnumerator.enumerate(simpleName)}; - return myCompoundKeyEnumerator.enumerate(classKey); + int[] classKey = new int[]{enumerateString(packageName), enumerateString(simpleName)}; + return enumerateCompoundKey(classKey); } - public int mkPsiKey(@NotNull PsiMethod psiMethod, Direction direction) throws IOException { + public long mkPsiKey(@NotNull PsiMethod psiMethod, Direction direction) throws IOException { final PsiClass psiClass = PsiTreeUtil.getParentOfType(psiMethod, PsiClass.class, false); if (psiClass == null) { LOG.debug("PsiClass was null for " + psiMethod.getName()); return -1; } - int sigKey = mkPsiSignatureKey(psiMethod); + long sigKey = mkPsiSignatureKey(psiMethod); if (sigKey == -1) { return -1; } - return myCompoundKeyEnumerator.enumerate(new int[]{mkDirectionKey(direction), sigKey}); - + long directionKey = mkDirectionKey(direction); + return sigKey * SHIFT + directionKey; } private int mkPsiSignatureKey(@NotNull PsiMethod psiMethod) throws IOException { @@ -228,21 +197,20 @@ public class BytecodeAnalysisConverter implements ApplicationComponent { final int shift = isInnerClassConstructor ? 1 : 0; final int arity = parameters.length + shift; - int[] shortSigKey = new int[3 + arity]; + int[] shortSigKey = new int[2 + arity]; if (returnType == null) { shortSigKey[0] = mkPsiTypeKey(PsiType.VOID); - shortSigKey[1] = myNamesEnumerator.enumerate("<init>"); + shortSigKey[1] = enumerateString("<init>"); } else { shortSigKey[0] = mkPsiTypeKey(returnType); - shortSigKey[1] = myNamesEnumerator.enumerate(psiMethod.getName()); + shortSigKey[1] = enumerateString(psiMethod.getName()); } - shortSigKey[2] = arity; if (isInnerClassConstructor) { - shortSigKey[3] = mkPsiClassKey(outerClass, 0); + shortSigKey[2] = mkPsiClassKey(outerClass, 0); } for (int i = 0; i < parameters.length; i++) { PsiParameter parameter = parameters[i]; - shortSigKey[3 + i + shift] = mkPsiTypeKey(parameter.getType()); + shortSigKey[2 + i + shift] = mkPsiTypeKey(parameter.getType()); } for (int aShortSigKey : shortSigKey) { if (aShortSigKey == -1) { @@ -256,9 +224,28 @@ public class BytecodeAnalysisConverter implements ApplicationComponent { return -1; } sigKey[0] = classKey; - sigKey[1] = myCompoundKeyEnumerator.enumerate(shortSigKey); + sigKey[1] = enumerateCompoundKey(shortSigKey); - return myCompoundKeyEnumerator.enumerate(sigKey); + return enumerateCompoundKey(sigKey); + } + + public TLongArrayList mkInOutKeys(@NotNull PsiMethod psiMethod, long primaryKey) throws IOException { + PsiParameter[] parameters = psiMethod.getParameterList().getParameters(); + TLongArrayList keys = new TLongArrayList(parameters.length * 2 + 1); + for (int i = 0; i < parameters.length; i++) { + PsiParameter parameter = parameters[i]; + PsiType parameterType = parameter.getType(); + if (parameterType instanceof PsiPrimitiveType) { + if (PsiType.BOOLEAN.equals(parameterType)) { + keys.add(primaryKey + mkDirectionKey(new InOut(i, Value.False))); + keys.add(primaryKey + mkDirectionKey(new InOut(i, Value.True))); + } + } else { + keys.add(primaryKey + mkDirectionKey(new InOut(i, Value.NotNull))); + keys.add(primaryKey + mkDirectionKey(new InOut(i, Value.Null))); + } + } + return keys; } @@ -279,17 +266,17 @@ public class BytecodeAnalysisConverter implements ApplicationComponent { className = qname.substring(packageName.length() + 1).replace('.', '$'); } int[] classKey = new int[2]; - classKey[0] = myNamesEnumerator.enumerate(packageName); + classKey[0] = enumerateString(packageName); if (dimensions == 0) { - classKey[1] = myNamesEnumerator.enumerate(className); + classKey[1] = enumerateString(className); } else { StringBuilder sb = new StringBuilder(className); for (int j = 0; j < dimensions; j++) { sb.append("[]"); } - classKey[1] = myNamesEnumerator.enumerate(sb.toString()); + classKey[1] = enumerateString(sb.toString()); } - return myCompoundKeyEnumerator.enumerate(classKey); + return enumerateCompoundKey(classKey); } private int mkPsiTypeKey(PsiType psiType) throws IOException { @@ -316,77 +303,69 @@ public class BytecodeAnalysisConverter implements ApplicationComponent { String packageName = ""; String className = psiType.getPresentableText(); int[] classKey = new int[2]; - classKey[0] = myNamesEnumerator.enumerate(packageName); + classKey[0] = enumerateString(packageName); if (dimensions == 0) { - classKey[1] = myNamesEnumerator.enumerate(className); + classKey[1] = enumerateString(className); } else { StringBuilder sb = new StringBuilder(className); for (int j = 0; j < dimensions; j++) { sb.append("[]"); } - classKey[1] = myNamesEnumerator.enumerate(sb.toString()); + classKey[1] = enumerateString(sb.toString()); } - return myCompoundKeyEnumerator.enumerate(classKey); + return enumerateCompoundKey(classKey); } return -1; } - public void addAnnotations(TIntObjectHashMap<Value> internalIdSolutions, Annotations annotations) { - - TIntObjectHashMap<List<String>> contractClauses = new TIntObjectHashMap<List<String>>(); - TIntObjectIterator<Value> solutionsIterator = internalIdSolutions.iterator(); + public void addMethodAnnotations(TLongObjectHashMap<Value> internalIdSolutions, Annotations annotations, long methodKey, int arity) { - TIntHashSet notNulls = annotations.notNulls; - TIntObjectHashMap<String> contracts = annotations.contracts; + List<String> clauses = new ArrayList<String>(); + TLongObjectIterator<Value> solutionsIterator = internalIdSolutions.iterator(); + TLongHashSet notNulls = annotations.notNulls; + TLongObjectHashMap<String> contracts = annotations.contracts; for (int i = internalIdSolutions.size(); i-- > 0;) { solutionsIterator.advance(); - int key = Math.abs(solutionsIterator.key()); + long key = Math.abs(solutionsIterator.key()); Value value = solutionsIterator.value(); if (value == Value.Top || value == Value.Bot) { continue; } - try { - int[] compoundKey = myCompoundKeyEnumerator.valueOf(key); - Direction direction = extractDirection(myCompoundKeyEnumerator.valueOf(compoundKey[0])); - if (value == Value.NotNull && (direction instanceof In || direction instanceof Out)) { - notNulls.add(key); - } - else if (direction instanceof InOut) { - compoundKey = new int[]{mkDirectionKey(new Out()), compoundKey[1]}; - try { - int baseKey = myCompoundKeyEnumerator.enumerate(compoundKey); - List<String> clauses = contractClauses.get(baseKey); - if (clauses == null) { - clauses = new ArrayList<String>(); - contractClauses.put(baseKey, clauses); - } - int[] sig = myCompoundKeyEnumerator.valueOf(compoundKey[1]); - int[] shortSig = myCompoundKeyEnumerator.valueOf(sig[1]); - int arity = shortSig[2]; - clauses.add(contractElement(arity, (InOut)direction, value)); - } - catch (IOException e) { - LOG.debug(e); - } - } + Direction direction = extractDirection((int)(key % SHIFT)); + if (value == Value.NotNull && direction instanceof Out && key == methodKey) { + notNulls.add(key); } - catch (IOException e) { - LOG.debug(e); + else if (direction instanceof InOut) { + long baseKey = key - (key % SHIFT); + if (baseKey == methodKey) { + clauses.add(contractElement(arity, (InOut)direction, value)); + } } } - TIntObjectIterator<List<String>> buildersIterator = contractClauses.iterator(); - for (int i = contractClauses.size(); i-- > 0;) { - buildersIterator.advance(); - int key = buildersIterator.key(); - if (!notNulls.contains(key)) { - List<String> clauses = buildersIterator.value(); - Collections.sort(clauses); - StringBuilder sb = new StringBuilder("\""); - StringUtil.join(clauses, ";", sb); - sb.append('"'); - contracts.put(key, sb.toString().intern()); + if (!notNulls.contains(methodKey) && !clauses.isEmpty()) { + Collections.sort(clauses); + StringBuilder sb = new StringBuilder("\""); + StringUtil.join(clauses, ";", sb); + sb.append('"'); + contracts.put(methodKey, sb.toString().intern()); + } + } + + public void addParameterAnnotations(TLongObjectHashMap<Value> internalIdSolutions, Annotations annotations) { + TLongObjectIterator<Value> solutionsIterator = internalIdSolutions.iterator(); + TLongHashSet notNulls = annotations.notNulls; + for (int i = internalIdSolutions.size(); i-- > 0;) { + solutionsIterator.advance(); + long key = Math.abs(solutionsIterator.key()); + Value value = solutionsIterator.value(); + if (value == Value.Top || value == Value.Bot) { + continue; + } + Direction direction = extractDirection((int)(key % SHIFT)); + if (value == Value.NotNull && (direction instanceof In || direction instanceof Out)) { + notNulls.add(key); } } } @@ -418,68 +397,4 @@ public class BytecodeAnalysisConverter implements ApplicationComponent { return sb.toString(); } - public int getVersion() { - return version; - } - - private static class IntArrayKeyDescriptor implements KeyDescriptor<int[]> { - - @Override - public void save(@NotNull DataOutput out, int[] value) throws IOException { - DataInputOutputUtil.writeINT(out, value.length); - for (int i : value) { - DataInputOutputUtil.writeINT(out, i); - } - } - - @Override - public int[] read(@NotNull DataInput in) throws IOException { - int[] value = new int[DataInputOutputUtil.readINT(in)]; - for (int i = 0; i < value.length; i++) { - value[i] = DataInputOutputUtil.readINT(in); - } - return value; - } - - @Override - public int getHashCode(int[] value) { - return Arrays.hashCode(value); - } - - @Override - public boolean isEqual(int[] val1, int[] val2) { - return Arrays.equals(val1, val2); - } - } - - private static class IntArrayPersistentEnumerator extends PersistentEnumeratorDelegate<int[]> { - private final CachingEnumerator<int[]> myCache; - - public IntArrayPersistentEnumerator(File compoundKeysFile, IntArrayKeyDescriptor descriptor) throws IOException { - super(compoundKeysFile, descriptor, 1024 * 4); - myCache = new CachingEnumerator<int[]>(new DataEnumerator<int[]>() { - @Override - public int enumerate(@Nullable int[] value) throws IOException { - return IntArrayPersistentEnumerator.super.enumerate(value); - } - - @Nullable - @Override - public int[] valueOf(int idx) throws IOException { - return IntArrayPersistentEnumerator.super.valueOf(idx); - } - }, descriptor); - } - - @Override - public int enumerate(@Nullable int[] value) throws IOException { - return myCache.enumerate(value); - } - - @Nullable - @Override - public int[] valueOf(int idx) throws IOException { - return myCache.valueOf(idx); - } - } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverterImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverterImpl.java new file mode 100644 index 000000000000..067cc743679e --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverterImpl.java @@ -0,0 +1,206 @@ +/* + * Copyright 2000-2014 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.bytecodeAnalysis; + +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.util.ThrowableComputable; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.io.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.*; +import java.io.DataOutputStream; +import java.util.Arrays; + +import static com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalysis.LOG; + +/** + * @author lambdamix + */ +public class BytecodeAnalysisConverterImpl extends BytecodeAnalysisConverter { + private static final int LOGIC_VERSION = 1; + private static final String ENUMERATORS_VERSION_KEY = "BytecodeAnalysisConverter.Enumerators"; + + private File myVersionFile; + private PersistentStringEnumerator myNamesEnumerator; + private PersistentEnumeratorDelegate<int[]> myCompoundKeyEnumerator; + private int version; + + @Override + public void initComponent() { + + // suffix as an indicator of version + final File keysDir = new File(PathManager.getIndexRoot(), "bytecodekeys"); + final File namesFile = new File(keysDir, "names" + LOGIC_VERSION); + final File compoundKeysFile = new File(keysDir, "compound" + LOGIC_VERSION); + myVersionFile = new File(keysDir, "version" + LOGIC_VERSION); + + version = PropertiesComponent.getInstance().getOrInitInt(ENUMERATORS_VERSION_KEY, 0); + if (ApplicationManager.getApplication().isUnitTestMode()) { + version = _readVersion(); + } + + if (!namesFile.exists() || !compoundKeysFile.exists() || !myVersionFile.exists()) { + LOG.info("No enumerators detected, re-initialization of enumerators."); + IOUtil.deleteAllFilesStartingWith(keysDir); + version++; + } + + try { + IOUtil.openCleanOrResetBroken(new ThrowableComputable<Void, IOException>() { + @Override + public Void compute() throws IOException { + myNamesEnumerator = new PersistentStringEnumerator(namesFile, true); + myCompoundKeyEnumerator = new IntArrayPersistentEnumerator(compoundKeysFile, new IntArrayKeyDescriptor()); + return null; + } + }, new Runnable() { + @Override + public void run() { + LOG.info("Error during initialization of enumerators in bytecode analysis. Re-initializing."); + IOUtil.deleteAllFilesStartingWith(keysDir); + version++; + } + }); + } + catch (IOException e) { + LOG.error("Re-initialization of enumerators in bytecode analysis failed.", e); + } + PropertiesComponent.getInstance().setValue(ENUMERATORS_VERSION_KEY, String.valueOf(version)); + _saveVersion(); + } + + @Override + public void disposeComponent() { + try { + myNamesEnumerator.close(); + myCompoundKeyEnumerator.close(); + } + catch (IOException e) { + LOG.debug(e); + } + } + + public int _readVersion() { + try { + final DataInputStream is = new DataInputStream(new FileInputStream(myVersionFile)); + try { + return is.readInt(); + } + finally { + is.close(); + } + } + catch (FileNotFoundException ignored) { + } + catch (IOException ignored) { + } + return 0; + } + + private void _saveVersion() { + try { + FileUtil.createIfDoesntExist(myVersionFile); + final DataOutputStream os = new DataOutputStream(new FileOutputStream(myVersionFile)); + try { + os.writeInt(version); + } + finally { + os.close(); + } + } + catch (IOException ignored) { + } + } + + public int getVersion() { + return version; + } + + @Override + protected int enumerateString(@NotNull String s) throws IOException { + return myNamesEnumerator.enumerate(s); + } + + @Override + protected int enumerateCompoundKey(@NotNull int[] key) throws IOException { + return myCompoundKeyEnumerator.enumerate(key); + } + + private static class IntArrayKeyDescriptor implements KeyDescriptor<int[]>, DifferentSerializableBytesImplyNonEqualityPolicy { + + @Override + public void save(@NotNull DataOutput out, int[] value) throws IOException { + DataInputOutputUtil.writeINT(out, value.length); + for (int i : value) { + DataInputOutputUtil.writeINT(out, i); + } + } + + @Override + public int[] read(@NotNull DataInput in) throws IOException { + int[] value = new int[DataInputOutputUtil.readINT(in)]; + for (int i = 0; i < value.length; i++) { + value[i] = DataInputOutputUtil.readINT(in); + } + return value; + } + + @Override + public int getHashCode(int[] value) { + return Arrays.hashCode(value); + } + + @Override + public boolean isEqual(int[] val1, int[] val2) { + return Arrays.equals(val1, val2); + } + } + + private static class IntArrayPersistentEnumerator extends PersistentEnumeratorDelegate<int[]> { + private final CachingEnumerator<int[]> myCache; + + public IntArrayPersistentEnumerator(File compoundKeysFile, IntArrayKeyDescriptor descriptor) throws IOException { + super(compoundKeysFile, descriptor, 1024 * 4); + myCache = new CachingEnumerator<int[]>(new DataEnumerator<int[]>() { + @Override + public int enumerate(@Nullable int[] value) throws IOException { + return IntArrayPersistentEnumerator.super.enumerate(value); + } + + @Nullable + @Override + public int[] valueOf(int idx) throws IOException { + return IntArrayPersistentEnumerator.super.valueOf(idx); + } + }, descriptor); + } + + @Override + public int enumerate(@Nullable int[] value) throws IOException { + return myCache.enumerate(value); + } + + @Nullable + @Override + public int[] valueOf(int idx) throws IOException { + return myCache.valueOf(idx); + } + } +} diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java index 6a4b32783c95..297b2b694c62 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java @@ -19,31 +19,29 @@ import com.intellij.ide.highlighter.JavaClassFileType; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.util.SystemProperties; import com.intellij.util.indexing.*; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.DataInputOutputUtil; -import com.intellij.util.io.EnumeratorIntegerDescriptor; +import com.intellij.util.io.DifferentSerializableBytesImplyNonEqualityPolicy; import com.intellij.util.io.KeyDescriptor; import org.jetbrains.annotations.NotNull; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; /** * @author lambdamix */ -public class BytecodeAnalysisIndex extends FileBasedIndexExtension<Integer, Collection<IntIdEquation>> { - public static final ID<Integer, Collection<IntIdEquation>> NAME = ID.create("bytecodeAnalysis"); +public class BytecodeAnalysisIndex extends FileBasedIndexExtension<Long, IdEquation> { + public static final ID<Long, IdEquation> NAME = ID.create("bytecodeAnalysis"); private final EquationExternalizer myExternalizer = new EquationExternalizer(); - private static final DataIndexer<Integer, Collection<IntIdEquation>, FileContent> INDEXER = + private static final DataIndexer<Long, IdEquation, FileContent> INDEXER = new ClassDataIndexer(BytecodeAnalysisConverter.getInstance()); + private static final SmartLongKeyDescriptor KEY_DESCRIPTOR = new SmartLongKeyDescriptor(); - private static final int ourInternalVersion = 2; + private static final int ourInternalVersion = 3; private static boolean ourEnabled = SystemProperties.getBooleanProperty("idea.enable.bytecode.contract.inference", isEnabledByDefault()); private static boolean isEnabledByDefault() { @@ -51,31 +49,27 @@ public class BytecodeAnalysisIndex extends FileBasedIndexExtension<Integer, Coll return application.isInternal() || application.isUnitTestMode(); } - public static int indexKey(VirtualFile file, boolean parameters) { - return (file instanceof VirtualFileWithId ? ((VirtualFileWithId)file).getId() * 2 : -2) + (parameters ? 1 : 0); - } - @NotNull @Override - public ID<Integer, Collection<IntIdEquation>> getName() { + public ID<Long, IdEquation> getName() { return NAME; } @NotNull @Override - public DataIndexer<Integer, Collection<IntIdEquation>, FileContent> getIndexer() { + public DataIndexer<Long, IdEquation, FileContent> getIndexer() { return INDEXER; } @NotNull @Override - public KeyDescriptor<Integer> getKeyDescriptor() { - return EnumeratorIntegerDescriptor.INSTANCE; + public KeyDescriptor<Long> getKeyDescriptor() { + return KEY_DESCRIPTOR; } @NotNull @Override - public DataExternalizer<Collection<IntIdEquation>> getValueExternalizer() { + public DataExternalizer<IdEquation> getValueExternalizer() { return myExternalizer; } @@ -100,68 +94,108 @@ public class BytecodeAnalysisIndex extends FileBasedIndexExtension<Integer, Coll return ourInternalVersion + BytecodeAnalysisConverter.getInstance().getVersion() + (ourEnabled ? 0xFF : 0); } - public static class EquationExternalizer implements DataExternalizer<Collection<IntIdEquation>> { + public static class EquationExternalizer implements DataExternalizer<IdEquation>, DifferentSerializableBytesImplyNonEqualityPolicy { @Override - public void save(@NotNull DataOutput out, Collection<IntIdEquation> equations) throws IOException { - DataInputOutputUtil.writeINT(out, equations.size()); - - for (IntIdEquation equation : equations) { - out.writeInt(equation.id); - IntIdResult rhs = equation.rhs; - if (rhs instanceof IntIdFinal) { - IntIdFinal finalResult = (IntIdFinal)rhs; - out.writeBoolean(true); // final flag - DataInputOutputUtil.writeINT(out, finalResult.value.ordinal()); - } else { - IntIdPending pendResult = (IntIdPending)rhs; - out.writeBoolean(false); // pending flag - DataInputOutputUtil.writeINT(out, pendResult.delta.length); - - for (IntIdComponent component : pendResult.delta) { - DataInputOutputUtil.writeINT(out, component.value.ordinal()); - int[] ids = component.ids; - DataInputOutputUtil.writeINT(out, ids.length); - for (int id : ids) { - out.writeInt(id); - } + public void save(@NotNull DataOutput out, IdEquation equation) throws IOException { + long id = equation.id; + int sign = id > 0 ? 1 : -1; + id = Math.abs(id); + int primaryId = (int)(id / BytecodeAnalysisConverter.SHIFT); + int secondaryId = (int)(id % BytecodeAnalysisConverter.SHIFT); + out.writeInt(sign * primaryId); + DataInputOutputUtil.writeINT(out, secondaryId); + IdResult rhs = equation.rhs; + if (rhs instanceof IdFinal) { + IdFinal finalResult = (IdFinal)rhs; + out.writeBoolean(true); // final flag + DataInputOutputUtil.writeINT(out, finalResult.value.ordinal()); + } else { + IdPending pendResult = (IdPending)rhs; + out.writeBoolean(false); // pending flag + DataInputOutputUtil.writeINT(out, pendResult.delta.length); + + for (IntIdComponent component : pendResult.delta) { + DataInputOutputUtil.writeINT(out, component.value.ordinal()); + long[] ids = component.ids; + DataInputOutputUtil.writeINT(out, ids.length); + for (long id1 : ids) { + sign = id1 > 0 ? 1 : -1; + id = Math.abs(id1); + primaryId = (int)(id / BytecodeAnalysisConverter.SHIFT); + secondaryId = (int)(id % BytecodeAnalysisConverter.SHIFT); + out.writeInt(sign * primaryId); + DataInputOutputUtil.writeINT(out, secondaryId); } } } } @Override - public Collection<IntIdEquation> read(@NotNull DataInput in) throws IOException { - - int size = DataInputOutputUtil.readINT(in); - ArrayList<IntIdEquation> result = new ArrayList<IntIdEquation>(size); - - for (int x = 0; x < size; x++) { - int equationId = in.readInt(); - boolean isFinal = in.readBoolean(); // flag - if (isFinal) { + public IdEquation read(@NotNull DataInput in) throws IOException { + long primaryId = in.readInt(); + int sign = primaryId > 0 ? 1 : -1; + primaryId = Math.abs(primaryId); + int secondaryId = DataInputOutputUtil.readINT(in); + long equationId = sign * (primaryId * BytecodeAnalysisConverter.SHIFT + secondaryId); + boolean isFinal = in.readBoolean(); // flag + if (isFinal) { + int ordinal = DataInputOutputUtil.readINT(in); + Value value = Value.values()[ordinal]; + return new IdEquation(equationId, new IdFinal(value)); + } else { + + int sumLength = DataInputOutputUtil.readINT(in); + IntIdComponent[] components = new IntIdComponent[sumLength]; + + for (int i = 0; i < sumLength; i++) { int ordinal = DataInputOutputUtil.readINT(in); Value value = Value.values()[ordinal]; - result.add(new IntIdEquation(equationId, new IntIdFinal(value))); - } else { - - int sumLength = DataInputOutputUtil.readINT(in); - IntIdComponent[] components = new IntIdComponent[sumLength]; - - for (int i = 0; i < sumLength; i++) { - int ordinal = DataInputOutputUtil.readINT(in); - Value value = Value.values()[ordinal]; - int componentSize = DataInputOutputUtil.readINT(in); - int[] ids = new int[componentSize]; - for (int j = 0; j < componentSize; j++) { - ids[j] = in.readInt(); - } - components[i] = new IntIdComponent(value, ids); + int componentSize = DataInputOutputUtil.readINT(in); + long[] ids = new long[componentSize]; + for (int j = 0; j < componentSize; j++) { + primaryId = in.readInt(); + sign = primaryId > 0 ? 1 : -1; + primaryId = Math.abs(primaryId); + secondaryId = DataInputOutputUtil.readINT(in); + long id = sign * (primaryId * BytecodeAnalysisConverter.SHIFT + secondaryId); + ids[j] = id; } - result.add(new IntIdEquation(equationId, new IntIdPending(components))); + components[i] = new IntIdComponent(value, ids); } + return new IdEquation(equationId, new IdPending(components)); } + } + } + + private static class SmartLongKeyDescriptor implements KeyDescriptor<Long>, DifferentSerializableBytesImplyNonEqualityPolicy { + @Override + public void save(@NotNull DataOutput out, Long value) throws IOException { + long id = value.longValue(); + int sign = id > 0 ? 1 : -1; + id = Math.abs(id); + int primaryId = (int)(id / BytecodeAnalysisConverter.SHIFT); + int secondaryId = (int)(id % BytecodeAnalysisConverter.SHIFT); + out.writeInt(primaryId * sign); + DataInputOutputUtil.writeINT(out, secondaryId); + } + + @Override + public Long read(@NotNull DataInput in) throws IOException { + long primaryId = in.readInt(); + int sign = primaryId > 0 ? 1 : -1; + primaryId = Math.abs(primaryId); + int secondaryId = DataInputOutputUtil.readINT(in); + return sign * (primaryId * BytecodeAnalysisConverter.SHIFT + secondaryId); + } - return result; + @Override + public int getHashCode(Long value) { + return value.hashCode(); + } + + @Override + public boolean isEqual(Long val1, Long val2) { + return val1.longValue() == val2.longValue(); } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java index 5e74a8b5dbb3..9e656b98a7fb 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java @@ -33,7 +33,7 @@ import static com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalys /** * @author lambdamix */ -public class ClassDataIndexer implements DataIndexer<Integer, Collection<IntIdEquation>, FileContent> { +public class ClassDataIndexer implements DataIndexer<Long, IdEquation, FileContent> { final BytecodeAnalysisConverter myConverter; public ClassDataIndexer(BytecodeAnalysisConverter converter) { @@ -42,25 +42,20 @@ public class ClassDataIndexer implements DataIndexer<Integer, Collection<IntIdEq @NotNull @Override - public Map<Integer, Collection<IntIdEquation>> map(@NotNull FileContent inputData) { - HashMap<Integer, Collection<IntIdEquation>> map = new HashMap<Integer, Collection<IntIdEquation>>(2); + public Map<Long, IdEquation> map(@NotNull FileContent inputData) { + HashMap<Long, IdEquation> map = new HashMap<Long, IdEquation>(); try { ClassEquations rawEquations = processClass(new ClassReader(inputData.getContent())); List<Equation<Key, Value>> rawParameterEquations = rawEquations.parameterEquations; List<Equation<Key, Value>> rawContractEquations = rawEquations.contractEquations; - Collection<IntIdEquation> idParameterEquations = new ArrayList<IntIdEquation>(rawParameterEquations.size()); - Collection<IntIdEquation> idContractEquations = new ArrayList<IntIdEquation>(rawContractEquations.size()); - - map.put(BytecodeAnalysisIndex.indexKey(inputData.getFile(), true), idParameterEquations); - map.put(BytecodeAnalysisIndex.indexKey(inputData.getFile(), false), idContractEquations); - - for (Equation<Key, Value> rawParameterEquation: rawParameterEquations) { - idParameterEquations.add(myConverter.convert(rawParameterEquation)); + IdEquation equation = myConverter.convert(rawParameterEquation); + map.put(equation.id, equation); } for (Equation<Key, Value> rawContractEquation: rawContractEquations) { - idContractEquations.add(myConverter.convert(rawContractEquation)); + IdEquation equation = myConverter.convert(rawContractEquation); + map.put(equation.id, equation); } } catch (ProcessCanceledException e) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java index c837b127b74b..7b6c52e75a63 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java @@ -49,7 +49,7 @@ class InOutAnalysis extends Analysis<Result<Key, Value>> { } @Override - Result<Key, Value> combineResults(Result<Key, Value> delta, List<Result<Key, Value>> subResults) { + Result<Key, Value> combineResults(Result<Key, Value> delta, List<Result<Key, Value>> subResults) throws AnalyzerException { Result<Key, Value> result = null; for (Result<Key, Value> subResult : subResults) { if (result == null) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java index 08c52c4d49b0..625eb8eed977 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java @@ -78,8 +78,9 @@ abstract class PResults { }; static final class ConditionalNPE implements PResult { final Set<Set<Key>> sop; - public ConditionalNPE(Set<Set<Key>> sop) { + public ConditionalNPE(Set<Set<Key>> sop) throws AnalyzerException { this.sop = sop; + checkLimit(sop); } public ConditionalNPE(Key key) { @@ -88,9 +89,19 @@ abstract class PResults { prod.add(key); sop.add(prod); } + + static void checkLimit(Set<Set<Key>> sop) throws AnalyzerException { + int size = 0; + for (Set<Key> keys : sop) { + size += keys.size(); + } + if (size > Analysis.EQUATION_SIZE_LIMIT) { + throw new AnalyzerException(null, "Equation size is too big"); + } + } } - static PResult join(PResult r1, PResult r2) { + static PResult join(PResult r1, PResult r2) throws AnalyzerException { if (Identity == r1) return r2; if (Identity == r2) return r1; if (Return == r1) return Return; @@ -102,7 +113,7 @@ abstract class PResults { return new ConditionalNPE(join(cnpe1.sop, cnpe2.sop)); } - static PResult meet(PResult r1, PResult r2) { + static PResult meet(PResult r1, PResult r2) throws AnalyzerException { if (Identity == r1) return r2; if (Return == r1) return r2; if (Return == r2) return r1; @@ -130,7 +141,7 @@ class NonNullInAnalysis extends Analysis<PResult> { } @Override - PResult combineResults(PResult delta, List<PResult> subResults) { + PResult combineResults(PResult delta, List<PResult> subResults) throws AnalyzerException { PResult subResult = Identity; for (PResult sr : subResults) { subResult = join(subResult, sr); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java index 86b9dd101fd9..23d9d5a9e1c5 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java @@ -15,34 +15,31 @@ */ package com.intellij.codeInspection.bytecodeAnalysis; -import com.intellij.ProjectTopics; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ContentIterator; -import com.intellij.openapi.roots.ModuleRootAdapter; -import com.intellij.openapi.roots.ModuleRootEvent; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.ModificationTracker; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.ProjectScope; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiFormatUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.LongStack; import com.intellij.util.indexing.FileBasedIndex; -import com.intellij.util.messages.MessageBusConnection; -import gnu.trove.TIntHashSet; -import gnu.trove.TIntObjectHashMap; +import gnu.trove.TLongArrayList; +import gnu.trove.TLongHashSet; +import gnu.trove.TLongObjectHashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.util.Collection; +import java.util.List; /** * @author lambdamix @@ -50,93 +47,15 @@ import java.util.Collection; public class ProjectBytecodeAnalysis { public static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.bytecodeAnalysis"); public static final Key<Boolean> INFERRED_ANNOTATION = Key.create("INFERRED_ANNOTATION"); + public static final int EQUATIONS_LIMIT = 1000; private final Project myProject; - private volatile Annotations myAnnotations = null; - public static ProjectBytecodeAnalysis getInstance(@NotNull Project project) { return ServiceManager.getService(project, ProjectBytecodeAnalysis.class); } public ProjectBytecodeAnalysis(Project project) { myProject = project; - final MessageBusConnection connection = myProject.getMessageBus().connect(); - connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() { - @Override - public void rootsChanged(ModuleRootEvent event) { - unloadAnnotations(); - } - }); - } - - private void loadAnnotations() { - Annotations annotations = new Annotations(); - loadParameterAnnotations(annotations); - loadContractAnnotations(annotations); - myAnnotations = annotations; - LOG.debug("NotNull annotations: " + myAnnotations.notNulls.size()); - LOG.debug("Contract annotations: " + myAnnotations.contracts.size()); - } - - private void unloadAnnotations() { - myAnnotations = null; - LOG.debug("unloaded"); - } - - private void loadParameterAnnotations(Annotations annotations) { - LOG.debug("initializing parameter annotations"); - final IntIdSolver solver = new IntIdSolver(new ELattice<Value>(Value.NotNull, Value.Top)); - - processValues(true, new FileBasedIndex.ValueProcessor<Collection<IntIdEquation>>() { - @Override - public boolean process(VirtualFile file, Collection<IntIdEquation> value) { - for (IntIdEquation intIdEquation : value) { - solver.addEquation(intIdEquation); - } - return true; - } - }); - - LOG.debug("parameter equations are constructed"); - LOG.debug("equations: " + solver.getSize()); - TIntObjectHashMap<Value> solutions = solver.solve(); - LOG.debug("parameter equations are solved"); - BytecodeAnalysisConverter.getInstance().addAnnotations(solutions, annotations); - } - - private void processValues(final boolean parameters, final FileBasedIndex.ValueProcessor<Collection<IntIdEquation>> processor) { - final GlobalSearchScope libScope = ProjectScope.getLibrariesScope(myProject); - final FileBasedIndex index = FileBasedIndex.getInstance(); - index.iterateIndexableFiles(new ContentIterator() { - @Override - public boolean processFile(VirtualFile fileOrDir) { - ProgressManager.checkCanceled(); - if (!fileOrDir.isDirectory() && libScope.contains(fileOrDir)) { - index.processValues(BytecodeAnalysisIndex.NAME, BytecodeAnalysisIndex.indexKey(fileOrDir, parameters), - fileOrDir, processor, GlobalSearchScope.fileScope(myProject, fileOrDir)); - } - return false; - } - }, myProject, null); - } - - private void loadContractAnnotations(Annotations annotations) { - LOG.debug("initializing contract annotations"); - final IntIdSolver solver = new IntIdSolver(new ELattice<Value>(Value.Bot, Value.Top)); - processValues(false, new FileBasedIndex.ValueProcessor<Collection<IntIdEquation>>() { - @Override - public boolean process(VirtualFile file, Collection<IntIdEquation> value) { - for (IntIdEquation intIdEquation : value) { - solver.addEquation(intIdEquation); - } - return true; - } - }); - LOG.debug("contract equations are constructed"); - LOG.debug("equations: " + solver.getSize()); - TIntObjectHashMap<Value> solutions = solver.solve(); - LOG.debug("contract equations are solved"); - BytecodeAnalysisConverter.getInstance().addAnnotations(solutions, annotations); } @Nullable @@ -144,11 +63,14 @@ public class ProjectBytecodeAnalysis { if (!(listOwner instanceof PsiCompiledElement)) { return null; } - if (annotationFQN.equals("org.jetbrains.annotations.NotNull")) { - return findNotNullAnnotation(listOwner); - } - else if (annotationFQN.equals("org.jetbrains.annotations.Contract")) { - return findContractAnnotation(listOwner); + if (annotationFQN.equals(AnnotationUtil.NOT_NULL) || annotationFQN.equals(ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT)) { + PsiAnnotation[] annotations = findInferredAnnotations(listOwner); + for (PsiAnnotation annotation : annotations) { + if (annotationFQN.equals(annotation.getQualifiedName())) { + return annotation; + } + } + return null; } else { return null; @@ -156,26 +78,30 @@ public class ProjectBytecodeAnalysis { } @NotNull - public PsiAnnotation[] findInferredAnnotations(@NotNull PsiModifierListOwner listOwner) { + public PsiAnnotation[] findInferredAnnotations(@NotNull final PsiModifierListOwner listOwner) { if (!(listOwner instanceof PsiCompiledElement)) { return PsiAnnotation.EMPTY_ARRAY; } - return collectInferredAnnotations(listOwner); + return CachedValuesManager.getCachedValue(listOwner, new CachedValueProvider<PsiAnnotation[]>() { + @Nullable + @Override + public Result<PsiAnnotation[]> compute() { + return Result.create(collectInferredAnnotations(listOwner), listOwner); + } + }); } - // TODO the best way to synchronize? @NotNull - private synchronized PsiAnnotation[] collectInferredAnnotations(PsiModifierListOwner listOwner) { - if (myAnnotations == null) { - loadAnnotations(); - } + private PsiAnnotation[] collectInferredAnnotations(PsiModifierListOwner listOwner) { try { - int key = getKey(listOwner); - if (key == -1) { + long ownerKey = getKey(listOwner); + if (ownerKey == -1) { return PsiAnnotation.EMPTY_ARRAY; } - boolean notNull = myAnnotations.notNulls.contains(key); - String contractValue = myAnnotations.contracts.get(key); + TLongArrayList allKeys = contractKeys(listOwner, ownerKey); + Annotations annotations = loadAnnotations(listOwner, ownerKey, allKeys); + boolean notNull = annotations.notNulls.contains(ownerKey); + String contractValue = annotations.contracts.get(ownerKey); if (notNull && contractValue != null) { return new PsiAnnotation[]{ @@ -201,6 +127,11 @@ public class ProjectBytecodeAnalysis { LOG.debug(e); return PsiAnnotation.EMPTY_ARRAY; } + catch (EquationsLimitException e) { + String externalName = PsiFormatUtil.getExternalName(listOwner, false, Integer.MAX_VALUE); + LOG.info("Too many equations for " + externalName); + return PsiAnnotation.EMPTY_ARRAY; + } } private PsiAnnotation getNotNullAnnotation() { @@ -213,54 +144,15 @@ public class ProjectBytecodeAnalysis { }); } - @Nullable - private synchronized PsiAnnotation findNotNullAnnotation(PsiModifierListOwner listOwner) { - if (myAnnotations == null) { - loadAnnotations(); - } - try { - int key = getKey(listOwner); - if (key == -1) { - return null; - } - return myAnnotations.notNulls.contains(key) ? getNotNullAnnotation() : null; - } - catch (IOException e) { - LOG.debug(e); - return null; - } - } - - @Nullable - private synchronized PsiAnnotation findContractAnnotation(PsiModifierListOwner listOwner) { - if (myAnnotations == null) { - loadAnnotations(); - } - try { - int key = getKey(listOwner); - if (key == -1) { - return null; - } - String contractValue = myAnnotations.contracts.get(key); - return contractValue != null ? createContractAnnotation(contractValue) : null; - } - catch (IOException e) { - LOG.debug(e); - return null; - } - } - public PsiAnnotation createContractAnnotation(String contractValue) { return createAnnotationFromText("@org.jetbrains.annotations.Contract(" + contractValue + ")"); } - public static int getKey(@NotNull PsiModifierListOwner owner) throws IOException { + public static long getKey(@NotNull PsiModifierListOwner owner) throws IOException { LOG.assertTrue(owner instanceof PsiCompiledElement, owner); - if (owner instanceof PsiMethod) { return BytecodeAnalysisConverter.getInstance().mkPsiKey((PsiMethod)owner, new Out()); } - if (owner instanceof PsiParameter) { PsiElement parent = owner.getParent(); if (parent instanceof PsiParameterList) { @@ -275,6 +167,80 @@ public class ProjectBytecodeAnalysis { return -1; } + public static TLongArrayList contractKeys(@NotNull PsiModifierListOwner owner, long primaryKey) throws IOException { + if (owner instanceof PsiMethod) { + TLongArrayList result = BytecodeAnalysisConverter.getInstance().mkInOutKeys((PsiMethod)owner, primaryKey); + result.add(primaryKey); + return result; + } + TLongArrayList result = new TLongArrayList(1); + result.add(primaryKey); + return result; + } + + private Annotations loadAnnotations(@NotNull PsiModifierListOwner owner, long key, TLongArrayList allKeys) + throws IOException, EquationsLimitException { + Annotations result = new Annotations(); + if (owner instanceof PsiParameter) { + final Solver solver = new Solver(new ELattice<Value>(Value.NotNull, Value.Top)); + collectEquations(allKeys, solver); + TLongObjectHashMap<Value> solutions = solver.solve(); + BytecodeAnalysisConverter.getInstance().addParameterAnnotations(solutions, result); + } else if (owner instanceof PsiMethod) { + final Solver solver = new Solver(new ELattice<Value>(Value.Bot, Value.Top)); + collectEquations(allKeys, solver); + TLongObjectHashMap<Value> solutions = solver.solve(); + BytecodeAnalysisConverter.getInstance().addMethodAnnotations(solutions, result, key, + ((PsiMethod)owner).getParameterList().getParameters().length); + } + return result; + } + + private void collectEquations(TLongArrayList keys, Solver solver) throws EquationsLimitException { + GlobalSearchScope librariesScope = ProjectScope.getLibrariesScope(myProject); + TLongHashSet queued = new TLongHashSet(); + LongStack queue = new LongStack(); + + for (int i = 0; i < keys.size(); i++) { + long key = keys.get(i); + queue.push(key); + queued.add(key); + // stable/unstable + queue.push(-key); + queued.add(-key); + } + + FileBasedIndex index = FileBasedIndex.getInstance(); + while (!queue.empty()) { + if (queued.size() > EQUATIONS_LIMIT) { + throw new EquationsLimitException(); + } + ProgressManager.checkCanceled(); + List<IdEquation> equations = index.getValues(BytecodeAnalysisIndex.NAME, queue.pop(), librariesScope); + for (IdEquation equation : equations) { + IdResult rhs = equation.rhs; + solver.addEquation(equation); + if (rhs instanceof IdPending) { + IdPending intIdPending = (IdPending)rhs; + for (IntIdComponent component : intIdPending.delta) { + for (long depKey : component.ids) { + if (!queued.contains(depKey)) { + queue.push(depKey); + queued.add(depKey); + } + // stable/unstable + long swapped = -depKey; + if (!queued.contains(swapped)) { + queue.push(swapped); + queued.add(swapped); + } + } + } + } + } + } + } + @NotNull private PsiAnnotation createAnnotationFromText(@NotNull final String text) throws IncorrectOperationException { PsiAnnotation annotation = JavaPsiFacade.getElementFactory(myProject).createAnnotationFromText(text, null); @@ -285,7 +251,9 @@ public class ProjectBytecodeAnalysis { class Annotations { // @NotNull keys - final TIntHashSet notNulls = new TIntHashSet(); + final TLongHashSet notNulls = new TLongHashSet(); // @Contracts - final TIntObjectHashMap<String> contracts = new TIntObjectHashMap<String>(); + final TLongObjectHashMap<String> contracts = new TLongObjectHashMap<String>(); } + +class EquationsLimitException extends Exception {} diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java index 47c97790d102..1dec1de8a606 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java @@ -15,10 +15,12 @@ */ package com.intellij.codeInspection.bytecodeAnalysis; -import com.intellij.util.containers.IntStack; -import com.intellij.util.containers.IntToIntSetMap; -import gnu.trove.TIntObjectHashMap; +import com.intellij.util.containers.LongStack; +import gnu.trove.TLongHashSet; +import gnu.trove.TLongIterator; +import gnu.trove.TLongObjectHashMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException; import java.util.*; @@ -49,9 +51,9 @@ final class ELattice<T extends Enum<T>> { // component specialized for ints final class IntIdComponent { Value value; - final int[] ids; + final long[] ids; - IntIdComponent(Value value, int[] ids) { + IntIdComponent(Value value, long[] ids) { this.value = value; this.ids = ids; } @@ -74,7 +76,7 @@ final class IntIdComponent { return value.ordinal() + Arrays.hashCode(ids); } - public boolean remove(int id) { + public boolean remove(long id) { return IdUtils.remove(ids, id); } @@ -89,18 +91,18 @@ final class IntIdComponent { class IdUtils { // removed value - static final int nullId = 0; + static final long nullId = 0; - static boolean contains(int[] ids, int id) { - for (int id1 : ids) { + static boolean contains(long[] ids, int id) { + for (long id1 : ids) { if (id1 == id) return true; } return false; } - static boolean isEmpty(int[] ids) { - for (int id : ids) { + static boolean isEmpty(long[] ids) { + for (long id : ids) { if (id != nullId) return false; } return true; @@ -117,7 +119,7 @@ class IdUtils { return result; } - static boolean remove(int[] ids, int id) { + static boolean remove(long[] ids, long id) { boolean removed = false; for (int i = 0; i < ids.length; i++) { if (ids[i] == id) { @@ -137,7 +139,7 @@ class ResultUtil<Id, T extends Enum<T>> { top = lattice.top; } - Result<Id, T> join(Result<Id, T> r1, Result<Id, T> r2) { + Result<Id, T> join(Result<Id, T> r1, Result<Id, T> r2) throws AnalyzerException { if (r1 instanceof Final && ((Final) r1).value == top) { return r1; } @@ -166,8 +168,19 @@ class ResultUtil<Id, T extends Enum<T>> { Set<Product<Id, T>> sum = new HashSet<Product<Id, T>>(); sum.addAll(pending1.sum); sum.addAll(pending2.sum); + checkLimit(sum); return new Pending<Id, T>(sum); } + + private void checkLimit(Set<Product<Id, T>> sum) throws AnalyzerException { + int size = 0; + for (Product<Id, T> prod : sum) { + size += prod.ids.size(); + } + if (size > Analysis.EQUATION_SIZE_LIMIT) { + throw new AnalyzerException(null, "Equation size is too big"); + } + } } final class Product<K, V> { @@ -222,11 +235,11 @@ final class Pending<Id, T> implements Result<Id, T> { } -interface IntIdResult {} +interface IdResult {} // this just wrapper, no need for this really -final class IntIdFinal implements IntIdResult { +final class IdFinal implements IdResult { final Value value; - public IntIdFinal(Value value) { + public IdFinal(Value value) { this.value = value; } @@ -235,7 +248,7 @@ final class IntIdFinal implements IntIdResult { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - IntIdFinal that = (IntIdFinal)o; + IdFinal that = (IdFinal)o; if (value != that.value) return false; @@ -253,19 +266,19 @@ final class IntIdFinal implements IntIdResult { } } -final class IntIdPending implements IntIdResult { +final class IdPending implements IdResult { final IntIdComponent[] delta; - IntIdPending(IntIdComponent[] delta) { + IdPending(IntIdComponent[] delta) { this.delta = delta; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof IntIdPending)) return false; - IntIdPending pending = (IntIdPending)o; - return !Arrays.equals(delta, pending.delta); + if (!(o instanceof IdPending)) return false; + IdPending pending = (IdPending)o; + return Arrays.equals(delta, pending.delta); } @Override @@ -273,20 +286,20 @@ final class IntIdPending implements IntIdResult { return Arrays.hashCode(delta); } - IntIdPending copy() { + IdPending copy() { IntIdComponent[] delta1 = new IntIdComponent[delta.length]; for (int i = 0; i < delta.length; i++) { delta1[i] = delta[i].copy(); } - return new IntIdPending(delta1); + return new IdPending(delta1); } } -final class IntIdEquation { - final int id; - final IntIdResult rhs; +final class IdEquation { + final long id; + final IdResult rhs; - IntIdEquation(int id, IntIdResult rhs) { + IdEquation(long id, IdResult rhs) { this.id = id; this.rhs = rhs; } @@ -294,9 +307,9 @@ final class IntIdEquation { @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof IntIdEquation)) return false; + if (!(o instanceof IdEquation)) return false; - IntIdEquation equation = (IntIdEquation)o; + IdEquation equation = (IdEquation)o; if (id != equation.id) return false; if (!rhs.equals(equation.rhs)) return false; @@ -306,9 +319,7 @@ final class IntIdEquation { @Override public int hashCode() { - int result = id; - result = 31 * result + rhs.hashCode(); - return result; + return 31 * ((int)(id ^ (id >>> 32))) + rhs.hashCode(); } } @@ -337,41 +348,46 @@ final class Equation<Id, T> { } } -final class IntIdSolver { +final class Solver { private int size = 0; private final ELattice<Value> lattice; - private final IntToIntSetMap dependencies = new IntToIntSetMap(10000, 0.5f); - private final TIntObjectHashMap<IntIdPending> pending = new TIntObjectHashMap<IntIdPending>(); - private final TIntObjectHashMap<Value> solved = new TIntObjectHashMap<Value>(); - private final IntStack moving = new IntStack(); + private final TLongObjectHashMap<TLongHashSet> dependencies = new TLongObjectHashMap<TLongHashSet>(); + private final TLongObjectHashMap<IdPending> pending = new TLongObjectHashMap<IdPending>(); + private final TLongObjectHashMap<Value> solved = new TLongObjectHashMap<Value>(); + private final LongStack moving = new LongStack(); int getSize() { return size; } - IntIdSolver(ELattice<Value> lattice) { + Solver(ELattice<Value> lattice) { this.lattice = lattice; } - void addEquation(IntIdEquation equation) { + void addEquation(IdEquation equation) { size ++; - IntIdResult rhs = equation.rhs; - if (rhs instanceof IntIdFinal) { - solved.put(equation.id, ((IntIdFinal) rhs).value); + IdResult rhs = equation.rhs; + if (rhs instanceof IdFinal) { + solved.put(equation.id, ((IdFinal) rhs).value); moving.push(equation.id); - } else if (rhs instanceof IntIdPending) { - IntIdPending pendResult = ((IntIdPending)rhs).copy(); - IntIdResult norm = normalize(pendResult.delta); - if (norm instanceof IntIdFinal) { - solved.put(equation.id, ((IntIdFinal) norm).value); + } else if (rhs instanceof IdPending) { + IdPending pendResult = ((IdPending)rhs).copy(); + IdResult norm = normalize(pendResult.delta); + if (norm instanceof IdFinal) { + solved.put(equation.id, ((IdFinal) norm).value); moving.push(equation.id); } else { - IntIdPending pendResult1 = ((IntIdPending)rhs).copy(); + IdPending pendResult1 = ((IdPending)rhs).copy(); for (IntIdComponent component : pendResult1.delta) { - for (int trigger : component.ids) { - dependencies.addOccurence(trigger, equation.id); + for (long trigger : component.ids) { + TLongHashSet set = dependencies.get(trigger); + if (set == null) { + set = new TLongHashSet(); + dependencies.put(trigger, set); + } + set.add(equation.id); } pending.put(equation.id, pendResult1); } @@ -379,31 +395,35 @@ final class IntIdSolver { } } - TIntObjectHashMap<Value> solve() { + TLongObjectHashMap<Value> solve() { while (!moving.empty()) { - int id = moving.pop(); + long id = moving.pop(); Value value = solved.get(id); boolean stable = id > 0; - int[] pIds = stable ? new int[]{id, -id} : new int[]{-id, id}; + long[] pIds = stable ? new long[]{id, -id} : new long[]{-id, id}; Value[] pVals = stable ? new Value[]{value, value} : new Value[]{value, lattice.top}; for (int i = 0; i < pIds.length; i++) { - int pId = pIds[i]; + long pId = pIds[i]; Value pVal = pVals[i]; - // todo - remove - int[] dIds = dependencies.get(pId); - for (int dId : dIds) { - IntIdPending pend = pending.remove(dId); + TLongHashSet dIds = dependencies.get(pId); + if (dIds == null) { + continue; + } + TLongIterator dIdsIterator = dIds.iterator(); + while (dIdsIterator.hasNext()) { + long dId = dIdsIterator.next(); + IdPending pend = pending.remove(dId); if (pend != null) { - IntIdResult pend1 = substitute(pend, pId, pVal); - if (pend1 instanceof IntIdFinal) { - IntIdFinal fi = (IntIdFinal)pend1; + IdResult pend1 = substitute(pend, pId, pVal); + if (pend1 instanceof IdFinal) { + IdFinal fi = (IdFinal)pend1; solved.put(dId, fi.value); moving.push(dId); } else { - pending.put(dId, (IntIdPending)pend1); + pending.put(dId, (IdPending)pend1); } } } @@ -414,7 +434,7 @@ final class IntIdSolver { } // substitute id -> value into pending - IntIdResult substitute(IntIdPending pending, int id, Value value) { + IdResult substitute(IdPending pending, long id, Value value) { IntIdComponent[] sum = pending.delta; for (IntIdComponent intIdComponent : sum) { if (intIdComponent.remove(id)) { @@ -424,7 +444,7 @@ final class IntIdSolver { return normalize(sum); } - IntIdResult normalize(IntIdComponent[] sum) { + IdResult normalize(IntIdComponent[] sum) { Value acc = lattice.bot; boolean computableNow = true; for (IntIdComponent prod : sum) { @@ -434,7 +454,7 @@ final class IntIdSolver { computableNow = false; } } - return (acc == lattice.top || computableNow) ? new IntIdFinal(acc) : new IntIdPending(sum); + return (acc == lattice.top || computableNow) ? new IdFinal(acc) : new IdPending(sum); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java index a1c908837ad0..bd207e58a0fe 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java @@ -71,7 +71,23 @@ class ContractInferenceInterpreter { if (statements.length == 1) { if (statements[0] instanceof PsiReturnStatement) { List<MethodContract> result = handleDelegation(((PsiReturnStatement)statements[0]).getReturnValue(), false); - if (result != null) return result; + if (result != null) { + PsiTypeElement typeElement = myMethod.getReturnTypeElement(); + final boolean returningObject = typeElement == null || !(typeElement.getType() instanceof PsiClassType); + return ContainerUtil.findAll(result, new Condition<MethodContract>() { + @Override + public boolean value(MethodContract contract) { + if ((contract.returnValue == NULL_VALUE || contract.returnValue == NOT_NULL_VALUE) && returningObject) { + return false; + } + if ((contract.returnValue == TRUE_VALUE || contract.returnValue == FALSE_VALUE) && !returningObject) { + return false; + } + + return true; + } + }); + } } else if (statements[0] instanceof PsiExpressionStatement && ((PsiExpressionStatement)statements[0]).getExpression() instanceof PsiMethodCallExpression) { List<MethodContract> result = handleDelegation(((PsiExpressionStatement)statements[0]).getExpression(), false); @@ -132,6 +148,9 @@ class ContractInferenceInterpreter { } else { answer = withConstraint(answer, paramIndex, argConstraint); + if (answer == null) { + return null; + } } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java index 691c2f00d985..1167210f917e 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java @@ -89,10 +89,16 @@ public class MethodContract { throw new ParseException("A contract clause must be in form arg1, ..., argN -> return-value"); } - String[] argStrings = clause.substring(0, arrowIndex).split(","); - ValueConstraint[] args = new ValueConstraint[argStrings.length]; - for (int i = 0; i < args.length; i++) { - args[i] = parseConstraint(argStrings[i]); + String beforeArrow = clause.substring(0, arrowIndex); + ValueConstraint[] args; + if (StringUtil.isNotEmpty(beforeArrow)) { + String[] argStrings = beforeArrow.split(","); + args = new ValueConstraint[argStrings.length]; + for (int i = 0; i < args.length; i++) { + args[i] = parseConstraint(argStrings[i]); + } + } else { + args = new ValueConstraint[0]; } result.add(new MethodContract(args, parseConstraint(clause.substring(arrowIndex + arrow.length())))); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 013e24cbe07a..36449128b494 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -500,21 +500,19 @@ public class StandardInstructionVisitor extends InstructionVisitor { PsiType varType = var.getVariableType(); if (!(varType instanceof PsiPrimitiveType)) return null; + + if (varType == PsiType.FLOAT || varType == PsiType.DOUBLE) return null; double minValue = varType == PsiType.BYTE ? Byte.MIN_VALUE : varType == PsiType.SHORT ? Short.MIN_VALUE : varType == PsiType.INT ? Integer.MIN_VALUE : varType == PsiType.CHAR ? Character.MIN_VALUE : - varType == PsiType.LONG ? Long.MIN_VALUE : - varType == PsiType.FLOAT ? Float.MIN_VALUE : - Double.MIN_VALUE; + Long.MIN_VALUE; double maxValue = varType == PsiType.BYTE ? Byte.MAX_VALUE : varType == PsiType.SHORT ? Short.MAX_VALUE : varType == PsiType.INT ? Integer.MAX_VALUE : varType == PsiType.CHAR ? Character.MAX_VALUE : - varType == PsiType.LONG ? Long.MAX_VALUE : - varType == PsiType.FLOAT ? Float.MAX_VALUE : - Double.MAX_VALUE; + Long.MAX_VALUE; return checkComparisonWithKnownRange(instruction, runner, memState, opSign, comparedWith, minValue, maxValue); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/xml/DeprecatedClassUsageInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/xml/DeprecatedClassUsageInspection.java index 0a914c0d4477..8c9e4a72dfef 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/xml/DeprecatedClassUsageInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/xml/DeprecatedClassUsageInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -20,7 +20,6 @@ import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.XmlSuppressableInspectionTool; import com.intellij.codeInspection.deprecation.DeprecationInspection; import com.intellij.psi.*; -import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.psi.xml.XmlTag; import com.intellij.util.ArrayUtil; @@ -46,11 +45,6 @@ public class DeprecatedClassUsageInspection extends XmlSuppressableInspectionToo } @Override - public void visitXmlAttribute(XmlAttribute attribute) { - checkReferences(attribute, holder); - } - - @Override public void visitXmlAttributeValue(XmlAttributeValue value) { checkReferences(value, holder); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java index b60094ffbd6f..ad53d9484959 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java @@ -138,8 +138,8 @@ public class PreferByKindWeigher extends LookupElementWeigher { qualifiedWithField, qualifiedWithGetter, superMethodParameters, - expectedTypeConstant, field, + expectedTypeConstant, getter, normal, collectionFactory, diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddMethodQualifierFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddMethodQualifierFix.java index ff851372e208..4ab9d43fbc1d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddMethodQualifierFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddMethodQualifierFix.java @@ -69,10 +69,14 @@ public class AddMethodQualifierFix implements IntentionAction { if (element == null || !element.isValid()) { return false; } + return getOrFindCandidates().size() != 0; + } + + private synchronized List<PsiVariable> getOrFindCandidates() { if (myCandidates == null) { findCandidates(); } - return myCandidates.size() != 0; + return myCandidates; } private void findCandidates() { @@ -84,6 +88,9 @@ public class AddMethodQualifierFix implements IntentionAction { } for (final PsiVariable var : CreateFromUsageUtils.guessMatchingVariables(methodCallElement)) { + if (var.getName() == null) { + continue; + } final PsiType type = var.getType(); if (!(type instanceof PsiClassType)) { continue; @@ -132,7 +139,7 @@ public class AddMethodQualifierFix implements IntentionAction { @NotNull @Override public String getTextFor(final PsiVariable value) { - return ObjectUtils.assertNotNull(value.getName()); + return value.getName(); } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AnonymousTargetClassPreselectionUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AnonymousTargetClassPreselectionUtil.java new file mode 100644 index 000000000000..421c43cabe88 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AnonymousTargetClassPreselectionUtil.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2014 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.codeInsight.daemon.impl.quickfix; + +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.psi.PsiAnonymousClass; +import com.intellij.psi.PsiClass; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +public class AnonymousTargetClassPreselectionUtil { + private static final String PRESELECT_ANONYMOUS = "create.member.preselect.anonymous"; + + public static void rememberSelection(PsiClass aClass, PsiClass firstClass) { + if (firstClass instanceof PsiAnonymousClass) { + PropertiesComponent.getInstance().setValue(PRESELECT_ANONYMOUS, String.valueOf(aClass == firstClass)); + } + } + + @Nullable + public static PsiClass getPreselection(Collection<PsiClass> classes, PsiClass firstClass) { + if (firstClass instanceof PsiAnonymousClass && !PropertiesComponent.getInstance().getBoolean(PRESELECT_ANONYMOUS, true)) { + for (PsiClass aClass : classes) { + if (!(aClass instanceof PsiAnonymousClass)) { + return aClass; + } + } + } + return null; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java index 09b83e2a489f..abe9368374e8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java @@ -119,7 +119,8 @@ public abstract class CreateFromUsageBaseFix extends BaseIntentionAction { protected abstract PsiElement getElement(); private void chooseTargetClass(List<PsiClass> classes, final Editor editor) { - final Project project = classes.get(0).getProject(); + final PsiClass firstClass = classes.get(0); + final Project project = firstClass.getProject(); final JList list = new JBList(classes); PsiElementListCellRenderer renderer = new PsiClassListCellRenderer(); @@ -128,12 +129,18 @@ public abstract class CreateFromUsageBaseFix extends BaseIntentionAction { final PopupChooserBuilder builder = new PopupChooserBuilder(list); renderer.installSpeedSearch(builder); + final PsiClass preselection = AnonymousTargetClassPreselectionUtil.getPreselection(classes, firstClass); + if (preselection != null) { + list.setSelectedValue(preselection, true); + } + Runnable runnable = new Runnable() { @Override public void run() { int index = list.getSelectedIndex(); if (index < 0) return; final PsiClass aClass = (PsiClass) list.getSelectedValue(); + AnonymousTargetClassPreselectionUtil.rememberSelection(aClass, firstClass); CommandProcessor.getInstance().executeCommand(project, new Runnable() { @Override public void run() { diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java index 906dfa6258de..e6991736c0e3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java @@ -144,6 +144,17 @@ public abstract class CopyPasteReferenceProcessor<TRef extends PsiElement> exten RangeMarker bounds, ReferenceData[] referenceData); + protected PsiElement resolveReferenceIgnoreOverriding(PsiPolyVariantReference reference) { + PsiElement referent = reference.resolve(); + if (referent == null) { + final ResolveResult[] results = reference.multiResolve(true); + if (results.length > 0) { + referent = results[0].getElement(); + } + } + return referent; + } + protected abstract void restoreReferences(ReferenceData[] referenceData, TRef[] refs); diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaCopyPasteReferenceProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaCopyPasteReferenceProcessor.java index 51edddd250aa..76be78b7932d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaCopyPasteReferenceProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaCopyPasteReferenceProcessor.java @@ -88,7 +88,8 @@ public class JavaCopyPasteReferenceProcessor extends CopyPasteReferenceProcessor } else { if (reference instanceof PsiReferenceExpression) { - PsiElement referent = reference.resolve(); + PsiElement referent = resolveReferenceIgnoreOverriding(reference); + if (!(referent instanceof PsiNamedElement) || !data.staticMemberName.equals(((PsiNamedElement)referent).getName()) || !(referent instanceof PsiMember) diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingCatchBodyFixer.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingCatchBodyFixer.java index 1d4d281aea68..08e06283d4a5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingCatchBodyFixer.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingCatchBodyFixer.java @@ -36,7 +36,7 @@ public class MissingCatchBodyFixer implements Fixer { final Document doc = editor.getDocument(); PsiCodeBlock body = catchSection.getCatchBlock(); - if (body != null && startLine(doc, body) == startLine(doc, catchSection)) return; + if (body != null && body.getLBrace() != null && body.getRBrace() != null) return; final PsiJavaToken rParenth = catchSection.getRParenth(); if (rParenth == null) return; @@ -44,7 +44,4 @@ public class MissingCatchBodyFixer implements Fixer { doc.insertString(rParenth.getTextRange().getEndOffset(), "{}"); } - private static int startLine(Document doc, PsiElement psiElement) { - return doc.getLineNumber(psiElement.getTextRange().getStartOffset()); - } }
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/PlainEnterProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/PlainEnterProcessor.java index 6bafcc00d983..884442c778cc 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/PlainEnterProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/PlainEnterProcessor.java @@ -83,6 +83,22 @@ public class PlainEnterProcessor implements EnterProcessor { @Nullable private static PsiCodeBlock getControlStatementBlock(int caret, PsiElement element) { + if (element instanceof PsiTryStatement) { + PsiCodeBlock tryBlock = ((PsiTryStatement)element).getTryBlock(); + if (tryBlock != null && caret < tryBlock.getTextRange().getEndOffset()) return tryBlock; + + for (PsiCodeBlock catchBlock : ((PsiTryStatement)element).getCatchBlocks()) { + if (catchBlock != null && caret < catchBlock.getTextRange().getEndOffset()) return catchBlock; + } + + return ((PsiTryStatement)element).getFinallyBlock(); + } + + if (element instanceof PsiMethod) { + PsiCodeBlock methodBody = ((PsiMethod)element).getBody(); + if (methodBody != null) return methodBody; + } + PsiStatement body = null; if (element instanceof PsiIfStatement) { body = ((PsiIfStatement)element).getThenBranch(); @@ -102,10 +118,6 @@ public class PlainEnterProcessor implements EnterProcessor { else if (element instanceof PsiDoWhileStatement) { body = ((PsiDoWhileStatement)element).getBody(); } - else if (element instanceof PsiMethod) { - PsiCodeBlock methodBody = ((PsiMethod)element).getBody(); - if (methodBody != null) return methodBody; - } return body instanceof PsiBlockStatement ? ((PsiBlockStatement)body).getCodeBlock() : null; } diff --git a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java index fd85d1124171..daf2e3002dd2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/hint/api/impls/MethodParameterInfoHandler.java @@ -450,18 +450,24 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc final PsiJavaCodeReferenceElement element = annotation.getNameReferenceElement(); if (element != null) { final PsiElement resolved = element.resolve(); - if (resolved instanceof PsiClass && !AnnotationUtil.isAnnotated((PsiClass)resolved, "java.lang.annotation.Documented", false)) continue; + if (resolved instanceof PsiClass && !AnnotationUtil.isAnnotated((PsiClass)resolved, "java.lang.annotation.Documented", false, true)) { + continue; + } String referenceName = element.getReferenceName(); - if (!shownAnnotations.add(referenceName)) continue; - - if (lastSize != buffer.length()) buffer.append(" "); - buffer.append("@").append(referenceName); + if (shownAnnotations.add(referenceName) || isRepeatableAnnotation(resolved)) { + if (lastSize != buffer.length()) buffer.append(" "); + buffer.append("@").append(referenceName); + } } } if (lastSize != buffer.length()) buffer.append(" "); } + private static boolean isRepeatableAnnotation(PsiElement resolved) { + return resolved instanceof PsiClass && !AnnotationUtil.isAnnotated((PsiModifierListOwner)resolved, CommonClassNames.JAVA_LANG_ANNOTATION_REPEATABLE, false, true); + } + @Override public void updateUI(final Object p, @NotNull final ParameterInfoUIContext context) { if (p instanceof CandidateInfo) { diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/FieldFromParameterUtils.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/FieldFromParameterUtils.java index ccec3c3cab07..37fb882e5e66 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/FieldFromParameterUtils.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/FieldFromParameterUtils.java @@ -187,14 +187,14 @@ public final class FieldFromParameterUtils { modifierList.setModifierProperty(PsiModifier.FINAL, isFinal); final NullableNotNullManager manager = NullableNotNullManager.getInstance(project); - final String nullable = manager.getNullable(parameter); - if (nullable != null) { - modifierList.addAfter(factory.createAnnotationFromText("@" + nullable, field), null); + final PsiAnnotation nullable = manager.getNullableAnnotation(parameter, false); + if (nullable != null && !manager.isContainerAnnotation(nullable)) { + modifierList.addAfter(factory.createAnnotationFromText("@" + nullable.getQualifiedName(), field), null); } else if (isFinal) { - final String notNull = manager.getNotNull(parameter); - if (notNull != null) { - modifierList.addAfter(factory.createAnnotationFromText("@" + notNull, field), null); + final PsiAnnotation notNull = manager.getNotNullAnnotation(parameter, false); + if (notNull != null && !manager.isContainerAnnotation(notNull)) { + modifierList.addAfter(factory.createAnnotationFromText("@" + notNull.getQualifiedName(), field), null); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/CastExpressionPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/CastExpressionPostfixTemplate.java index 952987a72c19..14059174cc16 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/CastExpressionPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/CastExpressionPostfixTemplate.java @@ -20,13 +20,17 @@ import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; -public class CastExpressionPostfixTemplate extends JavaPostfixTemplateWithChooser { +import static com.intellij.codeInsight.template.postfix.templates.PostfixTemplatesUtils.selectorWithChooser; +import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.IS_NON_VOID; +import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.JAVA_PSI_INFO; + +public class CastExpressionPostfixTemplate extends PostfixTemplateWithExpressionSelector { public CastExpressionPostfixTemplate() { - super("cast", "((SomeType) expr)"); + super("cast", "((SomeType) expr)", JAVA_PSI_INFO, selectorWithChooser(IS_NON_VOID)); } @Override - protected void doIt(@NotNull final Editor editor, @NotNull final PsiElement expression) { + protected void expandForChooseExpression(@NotNull PsiElement expression, @NotNull Editor editor) { PostfixTemplatesUtils.surround(new JavaWithCastSurrounder(), editor, expression); } }
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceFieldPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceFieldPostfixTemplate.java index 40da7fd94b88..2bac79d890bd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceFieldPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceFieldPostfixTemplate.java @@ -23,13 +23,17 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.introduceField.IntroduceFieldHandler; import org.jetbrains.annotations.NotNull; -public class IntroduceFieldPostfixTemplate extends JavaPostfixTemplateWithChooser { +import static com.intellij.codeInsight.template.postfix.templates.PostfixTemplatesUtils.selectorWithChooser; +import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.IS_NON_VOID; +import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.JAVA_PSI_INFO; + +public class IntroduceFieldPostfixTemplate extends PostfixTemplateWithExpressionSelector { public IntroduceFieldPostfixTemplate() { - super("field", "myField = expr"); + super("field", "myField = expr", JAVA_PSI_INFO, selectorWithChooser(IS_NON_VOID)); } @Override - protected void doIt(@NotNull Editor editor, @NotNull PsiElement expression) { + protected void expandForChooseExpression(@NotNull PsiElement expression, @NotNull Editor editor) { IntroduceFieldHandler handler = ApplicationManager.getApplication().isUnitTestMode() ? getMockHandler(expression) : new IntroduceFieldHandler(); handler.invoke(expression.getProject(), new PsiElement[]{expression}, null); diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceVariablePostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceVariablePostfixTemplate.java index 57c03f9501fa..be2dc23850e7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceVariablePostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/IntroduceVariablePostfixTemplate.java @@ -28,14 +28,18 @@ import com.intellij.refactoring.introduceVariable.IntroduceVariableSettings; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import org.jetbrains.annotations.NotNull; +import static com.intellij.codeInsight.template.postfix.templates.PostfixTemplatesUtils.selectorWithChooser; +import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.IS_NON_VOID; +import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.JAVA_PSI_INFO; + // todo: support for int[].var (parses as .class access!) -public class IntroduceVariablePostfixTemplate extends JavaPostfixTemplateWithChooser { +public class IntroduceVariablePostfixTemplate extends PostfixTemplateWithExpressionSelector { public IntroduceVariablePostfixTemplate() { - super("var", "T name = expr"); + super("var", "T name = expr", JAVA_PSI_INFO, selectorWithChooser(IS_NON_VOID)); } @Override - protected void doIt(@NotNull Editor editor, @NotNull PsiElement expression) { + protected void expandForChooseExpression(@NotNull PsiElement expression, @NotNull Editor editor) { // for advanced stuff use ((PsiJavaCodeReferenceElement)expression).advancedResolve(true).getElement(); IntroduceVariableHandler handler = ApplicationManager.getApplication().isUnitTestMode() ? getMockHandler() : new IntroduceVariableHandler(); diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/JavaPostfixTemplateProvider.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/JavaPostfixTemplateProvider.java index 148f4bb187db..629d4dd02115 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/JavaPostfixTemplateProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/JavaPostfixTemplateProvider.java @@ -144,6 +144,6 @@ public class JavaPostfixTemplateProvider implements PostfixTemplateProvider { } private static boolean isSemicolonNeeded(@NotNull PsiFile file, @NotNull Editor editor) { - return JavaCompletionContributor.semicolonNeeded(editor, file, CompletionInitializationContext.calcStartOffset(editor)); + return JavaCompletionContributor.semicolonNeeded(editor, file, CompletionInitializationContext.calcStartOffset(editor.getCaretModel().getCurrentCaret())); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/JavaPostfixTemplateWithChooser.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/JavaPostfixTemplateWithChooser.java deleted file mode 100644 index 72de706f4858..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/JavaPostfixTemplateWithChooser.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2000-2014 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.codeInsight.template.postfix.templates; - - -import com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils; -import com.intellij.openapi.util.Condition; -import com.intellij.psi.PsiElement; -import org.jetbrains.annotations.NotNull; - -import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.JAVA_PSI_INFO; - -public abstract class JavaPostfixTemplateWithChooser extends ExpressionPostfixTemplateWithChooser { - - - protected JavaPostfixTemplateWithChooser(@NotNull String name, @NotNull String example) { - super(name, example, JAVA_PSI_INFO); - } - - protected JavaPostfixTemplateWithChooser(@NotNull String name, @NotNull String key, @NotNull String example) { - super(name, key, example, JAVA_PSI_INFO); - } - - @NotNull - @Override - protected Condition<PsiElement> getTypeCondition() { - return JavaPostfixTemplatesUtils.IS_NON_VOID; - } -} diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/NotExpressionPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/NotExpressionPostfixTemplate.java index ac6f22c5092f..6160433cefe3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/NotExpressionPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/NotExpressionPostfixTemplate.java @@ -15,26 +15,16 @@ */ package com.intellij.codeInsight.template.postfix.templates; -import com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils; -import com.intellij.openapi.util.Condition; -import com.intellij.psi.PsiElement; -import org.jetbrains.annotations.NotNull; - +import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.IS_BOOLEAN; import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.JAVA_PSI_INFO; public class NotExpressionPostfixTemplate extends NotPostfixTemplate { public NotExpressionPostfixTemplate() { - super(JAVA_PSI_INFO); + super(JAVA_PSI_INFO, IS_BOOLEAN); } public NotExpressionPostfixTemplate(String alias) { - super(alias, alias, "!expr", JAVA_PSI_INFO); - } - - @NotNull - @Override - protected Condition<PsiElement> getTypeCondition() { - return JavaPostfixTemplatesUtils.IS_BOOLEAN; + super(alias, alias, "!expr", JAVA_PSI_INFO, IS_BOOLEAN); } }
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/ParenthesizedExpressionPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/ParenthesizedExpressionPostfixTemplate.java index 68b5c48fcd15..46c0c30b24f5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/ParenthesizedExpressionPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/ParenthesizedExpressionPostfixTemplate.java @@ -15,21 +15,11 @@ */ package com.intellij.codeInsight.template.postfix.templates; -import com.intellij.openapi.util.Condition; -import com.intellij.psi.PsiElement; -import org.jetbrains.annotations.NotNull; - import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.IS_NON_VOID; import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.JAVA_PSI_INFO; public class ParenthesizedExpressionPostfixTemplate extends ParenthesizedPostfixTemplate { public ParenthesizedExpressionPostfixTemplate() { - super(JAVA_PSI_INFO); - } - - @NotNull - @Override - protected Condition<PsiElement> getTypeCondition() { - return IS_NON_VOID; + super(JAVA_PSI_INFO, IS_NON_VOID); } }
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/util/JavaPostfixTemplatesUtils.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/util/JavaPostfixTemplatesUtils.java index e217175cdab9..2142c8fd33da 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/util/JavaPostfixTemplatesUtils.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/util/JavaPostfixTemplatesUtils.java @@ -16,7 +16,7 @@ package com.intellij.codeInsight.template.postfix.util; import com.intellij.codeInsight.CodeInsightServicesUtil; -import com.intellij.codeInsight.template.postfix.templates.PostfixTemplatePsiInfoBase; +import com.intellij.codeInsight.template.postfix.templates.PostfixTemplatePsiInfo; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.Condition; import com.intellij.psi.*; @@ -36,7 +36,7 @@ public abstract class JavaPostfixTemplatesUtils { private JavaPostfixTemplatesUtils() { } - public static final PostfixTemplatePsiInfoBase JAVA_PSI_INFO = new PostfixTemplatePsiInfoBase() { + public static final PostfixTemplatePsiInfo JAVA_PSI_INFO = new PostfixTemplatePsiInfo() { @NotNull @Override @@ -136,7 +136,11 @@ public abstract class JavaPostfixTemplatesUtils { @Contract("null -> false") public static boolean isNotPrimitiveTypeExpression(@Nullable PsiExpression expression) { - return expression != null && !(expression.getType() instanceof PsiPrimitiveType); + if (expression == null) { + return false; + } + PsiType type = expression.getType(); + return type != null && !(type instanceof PsiPrimitiveType); } @Contract("null -> false") diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java index aff69ec85da9..b3aed0603150 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java @@ -194,7 +194,7 @@ public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext final SearchScope searchScope = new GlobalSearchScope(refManager.getProject()) { @Override public boolean contains(@NotNull VirtualFile file) { - return !scope.contains(file) || file.getFileType() != StdFileTypes.JAVA; + return scope != null && !scope.contains(file) || file.getFileType() != StdFileTypes.JAVA; } @Override @@ -394,7 +394,7 @@ public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext @Override public boolean execute(PsiReference reference) { AnalysisScope scope = context.getRefManager().getScope(); - if (scope.contains(reference.getElement()) && reference.getElement().getLanguage() == StdLanguages.JAVA || + if (scope != null && scope.contains(reference.getElement()) && reference.getElement().getLanguage() == StdLanguages.JAVA || PsiTreeUtil.getParentOfType(reference.getElement(), PsiDocComment.class) != null) { return true; } diff --git a/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java b/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java index baab93de8d25..bcfea46a569c 100644 --- a/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java @@ -76,7 +76,7 @@ public class SameParameterValueInspection extends SameParameterValueInspectionBa public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) { final PsiElement element = descriptor.getPsiElement(); final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class); - LOG.assertTrue(method != null); + if (method == null) return; PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false); if (parameter == null) { final PsiParameter[] parameters = method.getParameterList().getParameters(); diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java index c33d0d68b8cb..bb97f5cd78d5 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java @@ -132,7 +132,7 @@ public class UnusedParametersInspection extends GlobalJavaBatchInspectionTool { int idx = refParameter.getIndex(); final boolean[] found = {false}; for (int i = 0; i < derived.length && !found[0]; i++) { - if (!scope.contains(derived[i])) { + if (scope == null || !scope.contains(derived[i])) { final PsiParameter[] parameters = derived[i].getParameterList().getParameters(); if (parameters.length >= idx) continue; PsiParameter psiParameter = parameters[idx]; diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java index 38ee7449994a..51beb4239fc3 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java @@ -63,7 +63,7 @@ public class FieldCanBeLocalInspection extends FieldCanBeLocalInspectionBase { @Override protected PsiElement moveDeclaration(@NotNull final Project project, @NotNull final PsiField variable) { final Map<PsiCodeBlock, Collection<PsiReference>> refs = new HashMap<PsiCodeBlock, Collection<PsiReference>>(); - groupByCodeBlocks(ReferencesSearch.search(variable).findAll(), refs); + if (!groupByCodeBlocks(ReferencesSearch.search(variable).findAll(), refs)) return null; PsiElement element = null; for (Collection<PsiReference> psiReferences : refs.values()) { element = super.moveDeclaration(project, variable, psiReferences, false); @@ -82,11 +82,14 @@ public class FieldCanBeLocalInspection extends FieldCanBeLocalInspectionBase { return element; } - private static void groupByCodeBlocks(final Collection<PsiReference> allReferences, Map<PsiCodeBlock, Collection<PsiReference>> refs) { + private static boolean groupByCodeBlocks(final Collection<PsiReference> allReferences, Map<PsiCodeBlock, Collection<PsiReference>> refs) { for (PsiReference psiReference : allReferences) { final PsiElement element = psiReference.getElement(); final PsiCodeBlock block = PsiTreeUtil.getTopmostParentOfType(element, PsiCodeBlock.class); - LOG.assertTrue(block != null); + if (block == null) { + return false; + } + Collection<PsiReference> references = refs.get(block); if (references == null) { references = new ArrayList<PsiReference>(); @@ -95,6 +98,7 @@ public class FieldCanBeLocalInspection extends FieldCanBeLocalInspectionBase { } references.add(psiReference); } + return true; } private static boolean findExistentBlock(Map<PsiCodeBlock, Collection<PsiReference>> refs, diff --git a/java/java-impl/src/com/intellij/ide/projectView/impl/PackageViewPane.java b/java/java-impl/src/com/intellij/ide/projectView/impl/PackageViewPane.java index 98f1fbeddfca..73fcc83df646 100644 --- a/java/java-impl/src/com/intellij/ide/projectView/impl/PackageViewPane.java +++ b/java/java-impl/src/com/intellij/ide/projectView/impl/PackageViewPane.java @@ -28,9 +28,7 @@ import com.intellij.ide.SelectInTarget; import com.intellij.ide.impl.PackagesPaneSelectInTarget; import com.intellij.ide.projectView.ProjectView; import com.intellij.ide.projectView.ViewSettings; -import com.intellij.ide.projectView.impl.nodes.PackageElement; -import com.intellij.ide.projectView.impl.nodes.PackageUtil; -import com.intellij.ide.projectView.impl.nodes.PackageViewProjectNode; +import com.intellij.ide.projectView.impl.nodes.*; import com.intellij.ide.util.DeleteHandler; import com.intellij.ide.util.treeView.AbstractTreeBuilder; import com.intellij.ide.util.treeView.AbstractTreeNode; @@ -48,8 +46,8 @@ import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPackage; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.PsiUtilBase; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -140,14 +138,30 @@ public final class PackageViewPane extends AbstractProjectViewPSIPane { @Override public PsiDirectory[] getSelectedDirectories() { - final PackageElement packageElement = getSelectedPackageElement(); - if (packageElement != null) { - final Module module = packageElement.getModule(); - final PsiPackage aPackage = packageElement.getPackage(); - if (module != null && aPackage != null) { - return aPackage.getDirectories(GlobalSearchScope.moduleScope(module)); + List<PsiDirectory> directories = ContainerUtil.newArrayList(); + for (PackageElementNode node : getSelectedNodes(PackageElementNode.class)) { + PackageElement packageElement = node.getValue(); + PsiPackage aPackage = packageElement != null ? packageElement.getPackage() : null; + final Module module = packageElement != null ? packageElement.getModule() : null; + if (aPackage != null && module != null) { + GlobalSearchScope scope = GlobalSearchScope.moduleScope(module); + Collections.addAll(directories, aPackage.getDirectories(scope)); + + Object parentValue = node.getParent().getValue(); + PsiPackage parentNodePackage = parentValue instanceof PackageElement ? ((PackageElement)parentValue).getPackage() : null; + while (true) { + aPackage = aPackage.getParentPackage(); + if (aPackage == null || aPackage.getQualifiedName().isEmpty() || aPackage.equals(parentNodePackage)) { + break; + } + Collections.addAll(directories, aPackage.getDirectories(scope)); + } } } + if (!directories.isEmpty()) { + return directories.toArray(new PsiDirectory[directories.size()]); + } + return super.getSelectedDirectories(); } diff --git a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultClassNavigationContributor.java b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultClassNavigationContributor.java index b0cbc06d048e..2f5418631dae 100644 --- a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultClassNavigationContributor.java +++ b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultClassNavigationContributor.java @@ -19,10 +19,14 @@ import com.intellij.navigation.ChooseByNameContributorEx; import com.intellij.navigation.GotoClassContributor; import com.intellij.navigation.NavigationItem; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiClass; +import com.intellij.psi.codeStyle.MinusculeMatcher; +import com.intellij.psi.codeStyle.NameUtil; import com.intellij.psi.presentation.java.SymbolPresentationUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; +import com.intellij.psi.util.ClassUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; @@ -32,6 +36,8 @@ import com.intellij.util.indexing.IdFilter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.regex.Matcher; + public class DefaultClassNavigationContributor implements ChooseByNameContributorEx, GotoClassContributor { @Override @NotNull @@ -74,7 +80,7 @@ public class DefaultClassNavigationContributor implements ChooseByNameContributo @Override public String getQualifiedNameSeparator() { - return "."; + return "$"; } @Override @@ -86,12 +92,28 @@ public class DefaultClassNavigationContributor implements ChooseByNameContributo public void processElementsWithName(@NotNull String name, @NotNull final Processor<NavigationItem> processor, @NotNull final FindSymbolParameters parameters) { + String namePattern = StringUtil.getShortName(parameters.getCompletePattern()); + boolean hasDollar = namePattern.contains("$"); + if (hasDollar) { + Matcher matcher = ChooseByNamePopup.patternToDetectAnonymousClasses.matcher(namePattern); + if (matcher.matches()) { + namePattern = matcher.group(1); + hasDollar = namePattern.contains("$"); + } + } + final MinusculeMatcher innerMatcher = hasDollar ? new MinusculeMatcher("*" + namePattern, NameUtil.MatchingCaseSensitivity.NONE) : null; PsiShortNamesCache.getInstance(parameters.getProject()).processClassesWithName(name, new Processor<PsiClass>() { final boolean isAnnotation = parameters.getLocalPatternName().startsWith("@"); + @Override public boolean process(PsiClass aClass) { if (aClass.getContainingFile().getVirtualFile() == null || !aClass.isPhysical()) return true; if (isAnnotation && !aClass.isAnnotationType()) return true; + if (innerMatcher != null) { + if (aClass.getContainingClass() == null) return true; + String jvmQName = ClassUtil.getJVMClassName(aClass); + if (jvmQName == null || !innerMatcher.matches(StringUtil.getShortName(jvmQName))) return true; + } return processor.process(aClass); } }, parameters.getSearchScope(), parameters.getIdFilter()); diff --git a/java/java-impl/src/com/intellij/openapi/roots/impl/ExcludeCompilerOutputPolicy.java b/java/java-impl/src/com/intellij/openapi/roots/impl/ExcludeCompilerOutputPolicy.java index adbacfcd38ce..c825d8318edc 100644 --- a/java/java-impl/src/com/intellij/openapi/roots/impl/ExcludeCompilerOutputPolicy.java +++ b/java/java-impl/src/com/intellij/openapi/roots/impl/ExcludeCompilerOutputPolicy.java @@ -15,16 +15,12 @@ */ package com.intellij.openapi.roots.impl; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.CompilerModuleExtension; import com.intellij.openapi.roots.CompilerProjectExtension; import com.intellij.openapi.roots.ModuleRootModel; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.pointers.VirtualFilePointer; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -40,26 +36,6 @@ public class ExcludeCompilerOutputPolicy implements DirectoryIndexExcludePolicy myProject = project; } - @Override - public boolean isExcludeRoot(final VirtualFile file) { - CompilerProjectExtension compilerProjectExtension = CompilerProjectExtension.getInstance(myProject); - if (isEqualWithFileOrUrl(file, compilerProjectExtension.getCompilerOutput(), compilerProjectExtension.getCompilerOutputUrl())) return true; - - for (Module m : ModuleManager.getInstance(myProject).getModules()) { - CompilerModuleExtension rm = CompilerModuleExtension.getInstance(m); - if (isEqualWithFileOrUrl(file, rm.getCompilerOutputPath(), rm.getCompilerOutputUrl())) return true; - if (isEqualWithFileOrUrl(file, rm.getCompilerOutputPathForTests(), rm.getCompilerOutputUrlForTests())) return true; - } - return false; - } - - @Override - public boolean isExcludeRootForModule(@NotNull final Module module, final VirtualFile excludeRoot) { - final CompilerModuleExtension compilerModuleExtension = CompilerModuleExtension.getInstance(module); - return Comparing.equal(compilerModuleExtension.getCompilerOutputPath(), excludeRoot) || - Comparing.equal(compilerModuleExtension.getCompilerOutputPathForTests(), excludeRoot); - } - @NotNull @Override public VirtualFile[] getExcludeRootsForProject() { @@ -88,14 +64,4 @@ public class ExcludeCompilerOutputPolicy implements DirectoryIndexExcludePolicy } return result.isEmpty() ? VirtualFilePointer.EMPTY_ARRAY : result.toArray(new VirtualFilePointer[result.size()]); } - - private static boolean isEqualWithFileOrUrl(VirtualFile file, VirtualFile fileToCompareWith, String url) { - if (fileToCompareWith != null) { - if (Comparing.equal(fileToCompareWith, file)) return true; - } - else if (url != null) { - if (FileUtil.pathsEqual(url, file.getUrl())) return true; - } - return false; - } } diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java index 3651fa1afe3a..ff1170b64bef 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java @@ -280,6 +280,7 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { if (ref instanceof PsiField && containingClassFields.contains(ref)) { referencedElements.add((PsiField)ref); } + super.visitReferenceExpression(expression); } }); diff --git a/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java b/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java index a8316f8dc0ee..eaa93875ba15 100644 --- a/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java +++ b/java/java-impl/src/com/intellij/psi/impl/search/JspIndexPatternBuilder.java @@ -18,6 +18,7 @@ package com.intellij.psi.impl.search; import com.intellij.lang.LanguageParserDefinitions; import com.intellij.lang.ParserDefinition; import com.intellij.lexer.Lexer; +import com.intellij.openapi.editor.impl.EditorHighlighterCache; import com.intellij.psi.JspPsiUtil; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.source.tree.StdTokenSets; @@ -34,7 +35,7 @@ public class JspIndexPatternBuilder implements IndexPatternBuilder { @Override public Lexer getIndexingLexer(@NotNull final PsiFile file) { if (JspPsiUtil.isInJspFile(file)) { - return LexerEditorHighlighterLexer.getLexerBasedOnLexerHighlighter(file.getText(), file.getVirtualFile(), file.getProject()); + return EditorHighlighterCache.getLexerBasedOnLexerHighlighter(file.getText(), file.getVirtualFile(), file.getProject()); } return null; diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java index 827a3d128a24..5380043307c7 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FilePathReferenceProvider.java @@ -142,9 +142,7 @@ public class FilePathReferenceProvider extends PsiReferenceProvider { @NotNull public static Collection<PsiFileSystemItem> getRoots(final Module thisModule, boolean includingClasses) { if (thisModule == null) return Collections.emptyList(); - Set<Module> modules = new com.intellij.util.containers.HashSet<Module>(); ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(thisModule); - ModuleUtilCore.getDependencies(thisModule, modules); List<PsiFileSystemItem> result = new ArrayList<PsiFileSystemItem>(); final PsiManager psiManager = PsiManager.getInstance(thisModule.getProject()); if (includingClasses) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/MethodPropertyReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/MethodPropertyReference.java index f7dc89ce5b80..307d608ddbd8 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/MethodPropertyReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/MethodPropertyReference.java @@ -16,7 +16,6 @@ package com.intellij.psi.impl.source.resolve.reference.impl.providers; import com.intellij.psi.*; -import com.intellij.psi.jsp.JspImplicitVariable; import com.intellij.psi.jsp.JspSpiUtil; import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.xml.XmlAttribute; @@ -62,8 +61,8 @@ public class MethodPropertyReference extends BasicAttributeValueReference { } } else if (psiElement instanceof PsiClass) { return (PsiClass)psiElement; - } else if (psiElement instanceof JspImplicitVariable) { - final PsiType type=((JspImplicitVariable)psiElement).getType(); + } else if (psiElement instanceof PsiVariable) { + final PsiType type=((PsiVariable)psiElement).getType(); if (type instanceof PsiClassType) { return ((PsiClassType)type).resolve(); } diff --git a/java/java-impl/src/com/intellij/refactoring/anonymousToInner/AnonymousToInnerDialog.java b/java/java-impl/src/com/intellij/refactoring/anonymousToInner/AnonymousToInnerDialog.java index 7bca3c07b4c0..80201559ef34 100644 --- a/java/java-impl/src/com/intellij/refactoring/anonymousToInner/AnonymousToInnerDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/anonymousToInner/AnonymousToInnerDialog.java @@ -86,20 +86,23 @@ class AnonymousToInnerDialog extends DialogWrapper{ final String[] names; String name = myAnonClass.getBaseClassReference().getReferenceName(); PsiType[] typeParameters = myAnonClass.getBaseClassReference().getTypeParameters(); - if (typeParameters.length > 0) { - names = new String[]{StringUtil.join(typeParameters, new Function<PsiType, String>() { - public String fun(PsiType psiType) { - PsiType type = psiType; - if (psiType instanceof PsiClassType) { - type = TypeConversionUtil.erasure(psiType); - } - if (type == null || type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return ""; - if (type instanceof PsiArrayType) { - type = type.getDeepComponentType(); - } - return StringUtil.getShortName(type.getPresentableText()); + + final String typeParamsList = StringUtil.join(typeParameters, new Function<PsiType, String>() { + public String fun(PsiType psiType) { + PsiType type = psiType; + if (psiType instanceof PsiClassType) { + type = TypeConversionUtil.erasure(psiType); } - }, "") + name, "My" + name}; + if (type == null || type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return ""; + if (type instanceof PsiArrayType) { + type = type.getDeepComponentType(); + } + return StringUtil.getShortName(type.getPresentableText()); + } + }, "") + name; + + if (!typeParamsList.equals(name)) { + names = new String[]{typeParamsList, "My" + name}; } else { names = new String[]{"My" + name}; } diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java index 75544f9d8ab9..ce52274140bb 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.ChangeContextUtil; import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil; +import com.intellij.codeInsight.daemon.impl.quickfix.AnonymousTargetClassPreselectionUtil; import com.intellij.codeInsight.highlighting.HighlightManager; import com.intellij.codeInsight.intention.impl.AddNullableAnnotationFix; import com.intellij.codeInsight.navigation.NavigationUtil; @@ -1133,6 +1134,7 @@ public class ExtractMethodProcessor implements MatchProvider { final PsiElementProcessor<PsiClass> processor = new PsiElementProcessor<PsiClass>() { @Override public boolean execute(@NotNull PsiClass selectedClass) { + AnonymousTargetClassPreselectionUtil.rememberSelection(selectedClass, myTargetClass); final List<PsiVariable> array = classes.get(selectedClass); myNeedChangeContext = myTargetClass != selectedClass; myTargetClass = selectedClass; @@ -1184,7 +1186,9 @@ public class ExtractMethodProcessor implements MatchProvider { if (classes.size() > 1) { final PsiClass[] psiClasses = classes.keySet().toArray(new PsiClass[classes.size()]); - NavigationUtil.getPsiElementPopup(psiClasses, new PsiClassListCellRenderer(), "Choose Destination Class", processor).showInBestPositionFor(myEditor); + final PsiClass preselection = AnonymousTargetClassPreselectionUtil.getPreselection(classes.keySet(), psiClasses[0]); + NavigationUtil.getPsiElementPopup(psiClasses, new PsiClassListCellRenderer(), "Choose Destination Class", processor, preselection) + .showInBestPositionFor(myEditor); return true; } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java index a751acea42df..75473959ddcc 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java @@ -27,6 +27,7 @@ package com.intellij.refactoring.introduceField; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.ChangeContextUtil; import com.intellij.codeInsight.TestFrameworks; +import com.intellij.codeInsight.daemon.impl.quickfix.AnonymousTargetClassPreselectionUtil; import com.intellij.codeInsight.highlighting.HighlightManager; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.navigation.NavigationUtil; @@ -129,18 +130,13 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase return !convertExpressionToField(selectedExpr, editor, file, project, tempType); } else { - PsiClass selection = null; - for (PsiClass psiClass : classes) { - if (!(psiClass instanceof PsiAnonymousClass)) { - selection = psiClass; - break; - } - } + PsiClass selection = AnonymousTargetClassPreselectionUtil.getPreselection(classes, myParentClass); NavigationUtil.getPsiElementPopup(classes.toArray(new PsiClass[classes.size()]), new PsiClassListCellRenderer(), "Choose class to introduce " + (myIsConstant ? "constant" : "field"), new PsiElementProcessor<PsiClass>() { @Override public boolean execute(@NotNull PsiClass aClass) { + AnonymousTargetClassPreselectionUtil.rememberSelection(aClass, myParentClass); myParentClass = aClass; convertExpressionToField(selectedExpr, editor, file, project, tempType); return false; diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java index 5b5c39fb10a8..0b31eedf8be0 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java @@ -18,6 +18,7 @@ package com.intellij.refactoring.introduceField; import com.intellij.codeInsight.ChangeContextUtil; import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.codeInsight.TestFrameworks; +import com.intellij.codeInsight.daemon.impl.quickfix.AnonymousTargetClassPreselectionUtil; import com.intellij.codeInsight.navigation.NavigationUtil; import com.intellij.ide.util.PsiClassListCellRenderer; import com.intellij.openapi.application.ApplicationManager; @@ -66,7 +67,7 @@ public abstract class LocalToFieldHandler { public boolean convertLocalToField(final PsiLocalVariable local, final Editor editor) { boolean tempIsStatic = myIsConstant; PsiElement parent = local.getParent(); - List<PsiClass> classes = new ArrayList<PsiClass>(); + final List<PsiClass> classes = new ArrayList<PsiClass>(); while (parent != null && parent.getContainingFile() != null) { if (parent instanceof PsiClass && !(myIsConstant && parent instanceof PsiAnonymousClass)) { classes.add((PsiClass)parent); @@ -90,13 +91,16 @@ public abstract class LocalToFieldHandler { if (convertLocalToField(local, classes.get(getChosenClassIndex(classes)), editor, tempIsStatic)) return false; } else { final boolean isStatic = tempIsStatic; + final PsiClass firstClass = classes.get(0); + final PsiClass preselection = AnonymousTargetClassPreselectionUtil.getPreselection(classes, firstClass); NavigationUtil.getPsiElementPopup(classes.toArray(new PsiClass[classes.size()]), new PsiClassListCellRenderer(), "Choose class to introduce " + (myIsConstant ? "constant" : "field"), new PsiElementProcessor<PsiClass>() { @Override public boolean execute(@NotNull PsiClass aClass) { + AnonymousTargetClassPreselectionUtil.rememberSelection(aClass, aClass); convertLocalToField(local, aClass, editor, isStatic); return false; } - }).showInBestPositionFor(editor); + }, preselection).showInBestPositionFor(editor); } return true; diff --git a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java index c410d763dac1..f09da834c348 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java @@ -210,10 +210,16 @@ public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor { if (element instanceof PsiReferenceExpression) { if (((PsiReferenceExpression)element).resolve() == methodToRename) { final PsiElement parent = element.getParent(); - LOG.assertTrue(parent instanceof PsiMethodCallExpression, parent.getText()); - final PsiMethodCallExpression copy = (PsiMethodCallExpression)JavaPsiFacade.getElementFactory(element.getProject()) - .createExpressionFromText(parent.getText(), element); - final PsiReferenceExpression expression = (PsiReferenceExpression)processRef(copy.getMethodExpression(), newName); + final PsiReferenceExpression copyRef; + if (parent instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression copy = (PsiMethodCallExpression)JavaPsiFacade.getElementFactory(element.getProject()) + .createExpressionFromText(parent.getText(), element); + copyRef = copy.getMethodExpression(); + } else { + LOG.assertTrue(element instanceof PsiMethodReferenceExpression, element.getText()); + copyRef = (PsiReferenceExpression)element.copy(); + } + final PsiReferenceExpression expression = (PsiReferenceExpression)processRef(copyRef, newName); if (expression == null) continue; final JavaResolveResult resolveResult = expression.advancedResolve(true); final PsiMember resolveResultElement = (PsiMember)resolveResult.getElement(); diff --git a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java index f2ac34e8aed0..ca01331d3e94 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java @@ -617,7 +617,7 @@ public class RefactoringUtil { Project project = expr.getProject(); String[] suggestedNames = JavaCodeStyleManager.getInstance(project).suggestVariableName(VariableKind.LOCAL_VARIABLE, null, expr, null).names; - final String prefix = suggestedNames[0]; + final String prefix = suggestedNames.length > 0 ? suggestedNames[0] : "var"; final String id = JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName(prefix, context, true); PsiElementFactory factory = JavaPsiFacade.getInstance(expr.getProject()).getElementFactory(); diff --git a/java/java-impl/src/com/intellij/testIntegration/createTest/MissedTestsDialog.java b/java/java-impl/src/com/intellij/testIntegration/createTest/MissedTestsDialog.java index b34d28e3f6f4..ee8bcf0d1c1c 100644 --- a/java/java-impl/src/com/intellij/testIntegration/createTest/MissedTestsDialog.java +++ b/java/java-impl/src/com/intellij/testIntegration/createTest/MissedTestsDialog.java @@ -20,19 +20,15 @@ import com.intellij.codeInsight.template.Template; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiMember; -import com.intellij.psi.PsiMethod; -import com.intellij.refactoring.ui.MemberSelectionPanel; +import com.intellij.psi.*; import com.intellij.refactoring.ui.MemberSelectionTable; import com.intellij.refactoring.util.classMembers.MemberInfo; import com.intellij.testIntegration.TestFramework; import com.intellij.testIntegration.TestIntegrationUtils; import com.intellij.ui.ScrollPaneFactory; -import com.intellij.ui.SeparatorFactory; import com.intellij.ui.components.JBCheckBox; import com.intellij.util.Function; +import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; @@ -40,8 +36,10 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.*; +import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; public class MissedTestsDialog extends DialogWrapper { private final PsiClass mySourceClass; @@ -85,9 +83,7 @@ public class MissedTestsDialog extends DialogWrapper { private void disableMethodsWithTests(List<MemberInfo> info) { final Set<String> existingNames = new HashSet<String>(); - final Template template = TestIntegrationUtils - .createTestMethodTemplate(TestIntegrationUtils.MethodKind.TEST, myDescriptor, myTestClass, null, true, existingNames); - final String prefix = JavaPsiFacade.getElementFactory(myTestClass.getProject()).createMethodFromText(template.getTemplateText(), myTestClass).getName(); + final String prefix = getTestPrefix(existingNames); existingNames.addAll(ContainerUtil.map(myTestClass.getMethods(), new Function<PsiMethod, String>() { @Override @@ -103,6 +99,16 @@ public class MissedTestsDialog extends DialogWrapper { } } + private String getTestPrefix(Set<String> existingNames) { + final Template template = TestIntegrationUtils.createTestMethodTemplate(TestIntegrationUtils.MethodKind.TEST, myDescriptor, myTestClass, null, true, existingNames); + try { + return JavaPsiFacade.getElementFactory(myTestClass.getProject()).createMethodFromText(template.getTemplateText(), myTestClass).getName(); + } + catch (IncorrectOperationException e) { + return ""; + } + } + private void updateMethodsTable() { List<MemberInfo> infos = TestIntegrationUtils.extractClassMethods(mySourceClass, myIncludeInheritedCb.isSelected()); diff --git a/java/java-impl/src/com/intellij/usages/impl/rules/JavaUsageTypeProvider.java b/java/java-impl/src/com/intellij/usages/impl/rules/JavaUsageTypeProvider.java index 445a8aab14a2..93b9737bdfe3 100644 --- a/java/java-impl/src/com/intellij/usages/impl/rules/JavaUsageTypeProvider.java +++ b/java/java-impl/src/com/intellij/usages/impl/rules/JavaUsageTypeProvider.java @@ -70,7 +70,8 @@ public class JavaUsageTypeProvider implements UsageTypeProviderEx { return UsageType.RECURSION; } if (qualifier != null && !(qualifier instanceof PsiThisExpression) && calledMethod != null) { - if (haveCommonSuperMethod(containerMethod, calledMethod)) { + if (Comparing.equal(containerMethod.getName(), calledMethod.getName()) && + haveCommonSuperMethod(containerMethod, calledMethod)) { boolean parametersDelegated = parametersDelegated(containerMethod, callExpression); if (qualifier instanceof PsiSuperExpression) { diff --git a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationTargetUtil.java b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationTargetUtil.java new file mode 100644 index 000000000000..c7d9e303aae3 --- /dev/null +++ b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationTargetUtil.java @@ -0,0 +1,136 @@ +/* + * Copyright 2000-2014 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.codeInsight; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.*; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.Set; + +/** + * @author peter + */ +public class AnnotationTargetUtil { + public static final Set<PsiAnnotation.TargetType> DEFAULT_TARGETS = Collections.unmodifiableSet(ContainerUtil.newHashSet( + PsiAnnotation.TargetType.PACKAGE, PsiAnnotation.TargetType.TYPE, PsiAnnotation.TargetType.ANNOTATION_TYPE, + PsiAnnotation.TargetType.FIELD, PsiAnnotation.TargetType.METHOD, PsiAnnotation.TargetType.CONSTRUCTOR, + PsiAnnotation.TargetType.PARAMETER, PsiAnnotation.TargetType.LOCAL_VARIABLE)); + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.AnnotationUtil"); + private static final PsiAnnotation.TargetType[] PACKAGE_TARGETS = {PsiAnnotation.TargetType.PACKAGE}; + private static final PsiAnnotation.TargetType[] TYPE_USE_TARGETS = {PsiAnnotation.TargetType.TYPE_USE}; + private static final PsiAnnotation.TargetType[] ANNOTATION_TARGETS = {PsiAnnotation.TargetType.ANNOTATION_TYPE, PsiAnnotation.TargetType.TYPE, PsiAnnotation.TargetType.TYPE_USE}; + private static final PsiAnnotation.TargetType[] TYPE_TARGETS = {PsiAnnotation.TargetType.TYPE, PsiAnnotation.TargetType.TYPE_USE}; + private static final PsiAnnotation.TargetType[] TYPE_PARAMETER_TARGETS = { + PsiAnnotation.TargetType.TYPE_PARAMETER, PsiAnnotation.TargetType.TYPE_USE}; + private static final PsiAnnotation.TargetType[] CONSTRUCTOR_TARGETS = {PsiAnnotation.TargetType.CONSTRUCTOR, PsiAnnotation.TargetType.TYPE_USE}; + private static final PsiAnnotation.TargetType[] METHOD_TARGETS = {PsiAnnotation.TargetType.METHOD, PsiAnnotation.TargetType.TYPE_USE}; + private static final PsiAnnotation.TargetType[] FIELD_TARGETS = {PsiAnnotation.TargetType.FIELD, PsiAnnotation.TargetType.TYPE_USE}; + private static final PsiAnnotation.TargetType[] PARAMETER_TARGETS = {PsiAnnotation.TargetType.PARAMETER, PsiAnnotation.TargetType.TYPE_USE}; + private static final PsiAnnotation.TargetType[] LOCAL_VARIABLE_TARGETS ={ + PsiAnnotation.TargetType.LOCAL_VARIABLE, PsiAnnotation.TargetType.TYPE_USE}; + + @NotNull + public static PsiAnnotation.TargetType[] getTargetsForLocation(@Nullable PsiAnnotationOwner owner) { + if (owner == null) { + return PsiAnnotation.TargetType.EMPTY_ARRAY; + } + + if (owner instanceof PsiType || owner instanceof PsiTypeElement) { + return TYPE_USE_TARGETS; + } + + if (owner instanceof PsiTypeParameter) { + return TYPE_PARAMETER_TARGETS; + } + + if (owner instanceof PsiModifierList) { + PsiElement element = ((PsiModifierList)owner).getParent(); + if (element instanceof PsiPackageStatement) { + return PACKAGE_TARGETS; + } + if (element instanceof PsiClass) { + if (((PsiClass)element).isAnnotationType()) { + return ANNOTATION_TARGETS; + } + else { + return TYPE_TARGETS; + } + } + if (element instanceof PsiMethod) { + if (((PsiMethod)element).isConstructor()) { + return CONSTRUCTOR_TARGETS; + } + else { + return METHOD_TARGETS; + } + } + if (element instanceof PsiField) { + return FIELD_TARGETS; + } + if (element instanceof PsiParameter) { + return PARAMETER_TARGETS; + } + if (element instanceof PsiLocalVariable) { + return LOCAL_VARIABLE_TARGETS; + } + } + + return PsiAnnotation.TargetType.EMPTY_ARRAY; + } + + @Nullable + public static Set<PsiAnnotation.TargetType> extractRequiredAnnotationTargets(@Nullable PsiAnnotationMemberValue value) { + if (value instanceof PsiReference) { + PsiAnnotation.TargetType targetType = translateTargetRef((PsiReference)value); + if (targetType != null) { + return Collections.singleton(targetType); + } + } + else if (value instanceof PsiArrayInitializerMemberValue) { + Set <PsiAnnotation.TargetType> targets = ContainerUtil.newHashSet(); + for (PsiAnnotationMemberValue initializer : ((PsiArrayInitializerMemberValue)value).getInitializers()) { + if (initializer instanceof PsiReference) { + PsiAnnotation.TargetType targetType = translateTargetRef((PsiReference)initializer); + if (targetType != null) { + targets.add(targetType); + } + } + } + return targets; + } + + return null; + } + + @Nullable + private static PsiAnnotation.TargetType translateTargetRef(@NotNull PsiReference reference) { + PsiElement field = reference.resolve(); + if (field instanceof PsiEnumConstant) { + String name = ((PsiEnumConstant)field).getName(); + try { + return PsiAnnotation.TargetType.valueOf(name); + } + catch (IllegalArgumentException e) { + LOG.warn("Unknown target: " + name); + } + } + return null; + } +} diff --git a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java index c2c79a9d9d8a..25034e9ab7ba 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java @@ -379,14 +379,14 @@ public class AnnotationUtil { @NotNull public static PsiAnnotation[] getAllAnnotations(@NotNull PsiModifierListOwner owner, boolean inHierarchy, - Set<PsiModifierListOwner> visited) { + @Nullable Set<PsiModifierListOwner> visited) { return getAllAnnotations(owner, inHierarchy, visited, true); } @NotNull public static PsiAnnotation[] getAllAnnotations(@NotNull PsiModifierListOwner owner, boolean inHierarchy, - Set<PsiModifierListOwner> visited, boolean withInferred) { + @Nullable Set<PsiModifierListOwner> visited, boolean withInferred) { final PsiModifierList list = owner.getModifierList(); PsiAnnotation[] annotations = PsiAnnotation.EMPTY_ARRAY; if (list != null) { diff --git a/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java b/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java index 21e014e4aca3..2210e02a080a 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java @@ -44,10 +44,13 @@ public class NullableNotNullManager implements PersistentStateComponent<Element> public final JDOMExternalizableStringList myNullables = new JDOMExternalizableStringList(); public final JDOMExternalizableStringList myNotNulls = new JDOMExternalizableStringList(); - public static final String[] DEFAULT_NULLABLES = {AnnotationUtil.NULLABLE, "javax.annotation.Nullable", + private static final String JAVAX_ANNOTATION_NULLABLE = "javax.annotation.Nullable"; + private static final String JAVAX_ANNOTATION_NONNULL = "javax.annotation.Nonnull"; + + public static final String[] DEFAULT_NULLABLES = {AnnotationUtil.NULLABLE, JAVAX_ANNOTATION_NULLABLE, "edu.umd.cs.findbugs.annotations.Nullable", "android.support.annotation.Nullable" }; - public static final String[] DEFAULT_NOT_NULLS = {AnnotationUtil.NOT_NULL, "javax.annotation.Nonnull", + public static final String[] DEFAULT_NOT_NULLS = {AnnotationUtil.NOT_NULL, JAVAX_ANNOTATION_NONNULL, "edu.umd.cs.findbugs.annotations.NonNull", "android.support.annotation.NonNull" }; @@ -103,6 +106,11 @@ public class NullableNotNullManager implements PersistentStateComponent<Element> return findNullabilityAnnotation(owner, checkBases, true); } + public boolean isContainerAnnotation(@NotNull PsiAnnotation anno) { + PsiAnnotation.TargetType[] acceptAnyTarget = PsiAnnotation.TargetType.values(); + return isNullabilityDefault(anno, true, acceptAnyTarget) || isNullabilityDefault(anno, false, acceptAnyTarget); + } + public void setDefaultNullable(@NotNull String defaultNullable) { LOG.assertTrue(getNullables().contains(defaultNullable)); myDefaultNullable = defaultNullable; @@ -138,15 +146,20 @@ public class NullableNotNullManager implements PersistentStateComponent<Element> return annotation; } - if (owner instanceof PsiParameter && !TypeConversionUtil.isPrimitiveAndNotNull(((PsiParameter)owner).getType())) { - // even if javax.annotation.Nullable is not configured, it should still take precedence over ByDefault annotations - if (AnnotationUtil.isAnnotated(owner, nullable ? Arrays.asList(DEFAULT_NOT_NULLS) : Arrays.asList(DEFAULT_NULLABLES), checkBases, false)) { - return null; - } - return findContainerAnnotation(owner, nullable - ? "javax.annotation.ParametersAreNullableByDefault" - : "javax.annotation.ParametersAreNonnullByDefault"); + PsiType type = getOwnerType(owner); + if (type == null || TypeConversionUtil.isPrimitiveAndNotNull(type)) return null; + + // even if javax.annotation.Nullable is not configured, it should still take precedence over ByDefault annotations + if (AnnotationUtil.isAnnotated(owner, nullable ? Arrays.asList(DEFAULT_NOT_NULLS) : Arrays.asList(DEFAULT_NULLABLES), checkBases, false)) { + return null; } + return findNullabilityDefaultInHierarchy(owner, nullable); + } + + @Nullable + private static PsiType getOwnerType(PsiModifierListOwner owner) { + if (owner instanceof PsiVariable) return ((PsiVariable)owner).getType(); + if (owner instanceof PsiMethod) return ((PsiMethod)owner).getReturnType(); return null; } @@ -159,11 +172,13 @@ public class NullableNotNullManager implements PersistentStateComponent<Element> } @Nullable - private static PsiAnnotation findContainerAnnotation(PsiModifierListOwner owner, String annotationFQN) { + private static PsiAnnotation findNullabilityDefaultInHierarchy(PsiModifierListOwner owner, boolean nullable) { + PsiAnnotation.TargetType[] placeTargetTypes = AnnotationTargetUtil.getTargetsForLocation(owner.getModifierList()); + PsiElement element = owner.getParent(); while (element != null) { if (element instanceof PsiModifierListOwner) { - PsiAnnotation annotation = AnnotationUtil.findAnnotation((PsiModifierListOwner)element, annotationFQN); + PsiAnnotation annotation = getNullabilityDefault((PsiModifierListOwner)element, nullable, placeTargetTypes); if (annotation != null) { return annotation; } @@ -172,7 +187,7 @@ public class NullableNotNullManager implements PersistentStateComponent<Element> if (element instanceof PsiClassOwner) { String packageName = ((PsiClassOwner)element).getPackageName(); PsiPackage psiPackage = JavaPsiFacade.getInstance(element.getProject()).findPackage(packageName); - return AnnotationUtil.findAnnotation(psiPackage, annotationFQN); + return psiPackage == null ? null : getNullabilityDefault(psiPackage, nullable, placeTargetTypes); } element = element.getContext(); @@ -180,6 +195,37 @@ public class NullableNotNullManager implements PersistentStateComponent<Element> return null; } + private static PsiAnnotation getNullabilityDefault(@NotNull PsiModifierListOwner container, boolean nullable, PsiAnnotation.TargetType[] placeTargetTypes) { + PsiModifierList modifierList = container.getModifierList(); + if (modifierList == null) return null; + for (PsiAnnotation annotation : modifierList.getAnnotations()) { + if (isNullabilityDefault(annotation, nullable, placeTargetTypes)) { + return annotation; + } + } + return null; + } + + private static boolean isNullabilityDefault(@NotNull PsiAnnotation annotation, boolean nullable, PsiAnnotation.TargetType[] placeTargetTypes) { + PsiJavaCodeReferenceElement element = annotation.getNameReferenceElement(); + PsiElement declaration = element == null ? null : element.resolve(); + if (!(declaration instanceof PsiClass)) return false; + + if (!AnnotationUtil.isAnnotated((PsiClass)declaration, + nullable ? JAVAX_ANNOTATION_NULLABLE : JAVAX_ANNOTATION_NONNULL, + false, + true)) { + return false; + } + + PsiAnnotation tqDefault = AnnotationUtil.findAnnotation((PsiClass)declaration, true, "javax.annotation.meta.TypeQualifierDefault"); + if (tqDefault == null) return false; + + Set<PsiAnnotation.TargetType> required = AnnotationTargetUtil.extractRequiredAnnotationTargets(tqDefault.findAttributeValue(null)); + if (required == null) return false; + return required.isEmpty() || ContainerUtil.intersects(required, Arrays.asList(placeTargetTypes)); + } + public List<String> getNullables() { return myNullables; } diff --git a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java index 7cabc118fc6c..52888f123215 100644 --- a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java @@ -476,6 +476,9 @@ public class GenericsUtil { PsiType substituted = resolveResult.getSubstitutor().substitute(typeParam); if (substituted instanceof PsiWildcardType) { substituted = ((PsiWildcardType)substituted).getBound(); + if (substituted instanceof PsiCapturedWildcardType) { + substituted = ((PsiCapturedWildcardType)substituted).getWildcard().getBound(); + } if (substituted == null) substituted = TypeConversionUtil.typeParameterErasure(typeParam); } map.put(typeParam, substituted); diff --git a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java index e7506ebd92fd..f43358007eab 100644 --- a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java +++ b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java @@ -180,7 +180,7 @@ public class MethodCandidateInfo extends CandidateInfo{ @NotNull public PsiSubstitutor getSubstitutor(boolean includeReturnConstraint) { PsiSubstitutor substitutor = myCalcedSubstitutor; - if (substitutor == null || !includeReturnConstraint && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { + if (substitutor == null || !includeReturnConstraint && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) || isOverloadCheck()) { PsiSubstitutor incompleteSubstitutor = super.getSubstitutor(); PsiMethod method = getElement(); if (myTypeArguments == null) { @@ -189,7 +189,7 @@ public class MethodCandidateInfo extends CandidateInfo{ final PsiSubstitutor inferredSubstitutor = inferTypeArguments(DefaultParameterTypeInferencePolicy.INSTANCE, includeReturnConstraint); if (!stackStamp.mayCacheNow() || - !ourOverloadGuard.currentStack().isEmpty() || + isOverloadCheck() || !includeReturnConstraint && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) || getMarkerList() != null && PsiResolveHelper.ourGraphGuard.currentStack().contains(getMarkerList().getParent())) { return inferredSubstitutor; @@ -209,6 +209,10 @@ public class MethodCandidateInfo extends CandidateInfo{ return substitutor; } + public static boolean isOverloadCheck() { + return !ourOverloadGuard.currentStack().isEmpty(); + } + public boolean isTypeArgumentsApplicable() { return isTypeArgumentsApplicable(false); diff --git a/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureUtil.java b/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureUtil.java index 622714c6dd61..22591801e32e 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureUtil.java @@ -114,7 +114,7 @@ public class MethodSignatureUtil { } public static boolean areSignaturesEqual(@NotNull PsiMethod method1, @NotNull PsiMethod method2) { - return method1.getSignature(PsiSubstitutor.EMPTY).equals(method2.getSignature(PsiSubstitutor.EMPTY)); + return areSignaturesEqual(method1.getSignature(PsiSubstitutor.EMPTY), method2.getSignature(PsiSubstitutor.EMPTY)); } public static boolean areSignaturesEqual(@NotNull MethodSignature method1, @NotNull MethodSignature method2) { @@ -172,10 +172,10 @@ public class MethodSignatureUtil { public static boolean isSuperMethod(@NotNull PsiMethod superMethodCandidate, @NotNull PsiMethod derivedMethod) { PsiClass superClassCandidate = superMethodCandidate.getContainingClass(); PsiClass derivedClass = derivedMethod.getContainingClass(); - if (derivedClass == null || superClassCandidate == null) return false; - if (!derivedClass.isInheritor(superClassCandidate, true)) return false; - final PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClassCandidate, derivedClass, - PsiSubstitutor.EMPTY); + if (derivedClass == null || superClassCandidate == null || derivedClass == superClassCandidate) return false; + final PsiSubstitutor superSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(superClassCandidate, derivedClass, + PsiSubstitutor.EMPTY, null); + if (superSubstitutor == null) return false; final MethodSignature superSignature = superMethodCandidate.getSignature(superSubstitutor); final MethodSignature derivedSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY); return isSubsignature(superSignature, derivedSignature); diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java index e5493711b7c2..a69e11a9d3cc 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java @@ -1099,6 +1099,11 @@ public final class PsiUtil extends PsiUtilCore { return true; } } + else if (parent instanceof PsiConditionalExpression) { + if (checkSameExpression(expr, ((PsiConditionalExpression)parent).getCondition())) { + return true; + } + } return false; } diff --git a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java index 477a74e64b2e..42f1494bad2e 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java @@ -128,6 +128,9 @@ public class TypeConversionUtil { return boxedType != null && areTypesConvertible(boxedType, toType); } if (!fromIsPrimitive) { + // 5.5. Casting Contexts + if ((fromTypeRank == SHORT_RANK || fromTypeRank == BYTE_RANK) && toTypeRank == CHAR_RANK) return false; + if (fromType instanceof PsiClassType) { if (languageLevel == null) { languageLevel = ((PsiClassType)fromType).getLanguageLevel(); @@ -162,7 +165,7 @@ public class TypeConversionUtil { /** * see JLS 5.1.5, JLS3 5.1.6 */ - private static boolean isNarrowingReferenceConversionAllowed(PsiType fromType, PsiType toType) { + private static boolean isNarrowingReferenceConversionAllowed(@NotNull PsiType fromType, @NotNull PsiType toType) { if (toType instanceof PsiPrimitiveType || fromType instanceof PsiPrimitiveType) return fromType.equals(toType); //Done with primitives if (toType instanceof PsiDiamondType || fromType instanceof PsiDiamondType) return false; @@ -280,60 +283,56 @@ public class TypeConversionUtil { return false; } } - else { - if (!toClass.isInterface()) { - if (!toClass.hasModifierProperty(PsiModifier.FINAL)) { - return checkSuperTypesWithDifferentTypeArguments(fromResult, toClass, manager, toResult.getSubstitutor(), null, languageLevel); - } - else { - if (!toClass.isInheritor(fromClass, true)) return false; - PsiSubstitutor toSubstitutor = getSuperClassSubstitutor(fromClass, toClass, toResult.getSubstitutor()); - return areSameArgumentTypes(fromClass, fromResult.getSubstitutor(), toSubstitutor); - } + else if (!toClass.isInterface()) { + if (!toClass.hasModifierProperty(PsiModifier.FINAL)) { + return checkSuperTypesWithDifferentTypeArguments(fromResult, toClass, manager, toResult.getSubstitutor(), null, languageLevel); } else { - if (languageLevel.compareTo(LanguageLevel.JDK_1_5) < 0) { - //In jls2 check for method in both interfaces with the same signature but different return types. - Collection<HierarchicalMethodSignature> fromClassMethodSignatures = fromClass.getVisibleSignatures(); - Collection<HierarchicalMethodSignature> toClassMethodSignatures = toClass.getVisibleSignatures(); - - for (HierarchicalMethodSignature fromMethodSignature : fromClassMethodSignatures) { - for (HierarchicalMethodSignature toMethodSignature : toClassMethodSignatures) { - if (fromMethodSignature.equals(toMethodSignature)) { - final PsiType fromClassReturnType = fromMethodSignature.getMethod().getReturnType(); - final PsiType toClassReturnType = toMethodSignature.getMethod().getReturnType(); - if (fromClassReturnType != null - && toClassReturnType != null - && !fromClassReturnType.equals(toClassReturnType)) { - return false; - } - } + PsiSubstitutor toSubstitutor = getMaybeSuperClassSubstitutor(fromClass, toClass, toResult.getSubstitutor(), null); + return toSubstitutor != null && areSameArgumentTypes(fromClass, fromResult.getSubstitutor(), toSubstitutor); + } + } + else if (languageLevel.compareTo(LanguageLevel.JDK_1_5) < 0) { + //In jls2 check for method in both interfaces with the same signature but different return types. + Collection<HierarchicalMethodSignature> fromClassMethodSignatures = fromClass.getVisibleSignatures(); + Collection<HierarchicalMethodSignature> toClassMethodSignatures = toClass.getVisibleSignatures(); + + for (HierarchicalMethodSignature fromMethodSignature : fromClassMethodSignatures) { + for (HierarchicalMethodSignature toMethodSignature : toClassMethodSignatures) { + if (fromMethodSignature.equals(toMethodSignature)) { + final PsiType fromClassReturnType = fromMethodSignature.getMethod().getReturnType(); + final PsiType toClassReturnType = toMethodSignature.getMethod().getReturnType(); + if (fromClassReturnType != null + && toClassReturnType != null + && !fromClassReturnType.equals(toClassReturnType)) { + return false; } } - return true; - } - else { - //In jls3 check for super interface with distinct type arguments - PsiClassType.ClassResolveResult baseResult; - PsiClass derived; - PsiSubstitutor derivedSubstitutor; - if (toClass.isInheritor(fromClass, true)) { - baseResult = fromResult; - derived = toClass; - derivedSubstitutor = toResult.getSubstitutor(); - } - else { - baseResult = toResult; - derived = fromClass; - derivedSubstitutor = fromResult.getSubstitutor(); - } - return checkSuperTypesWithDifferentTypeArguments(baseResult, derived, manager, derivedSubstitutor, null, languageLevel); } } + return true; + } + else { + //In jls3 check for super interface with distinct type arguments + PsiClassType.ClassResolveResult baseResult; + PsiClass derived; + PsiSubstitutor derivedSubstitutor; + if (toClass.isInheritor(fromClass, true)) { + baseResult = fromResult; + derived = toClass; + derivedSubstitutor = toResult.getSubstitutor(); + } + else { + baseResult = toResult; + derived = fromClass; + derivedSubstitutor = fromResult.getSubstitutor(); + } + return checkSuperTypesWithDifferentTypeArguments(baseResult, derived, manager, derivedSubstitutor, null, languageLevel); } } - private static PsiClassType obtainSafeSuperType(final PsiTypeParameter typeParameter) { + @NotNull + private static PsiClassType obtainSafeSuperType(@NotNull PsiTypeParameter typeParameter) { final PsiClassType superType = typeParameter.getSuperTypes()[0]; final PsiClassType.ClassResolveResult result = superType.resolveGenerics(); final PsiClass superClass = result.getElement(); @@ -344,12 +343,12 @@ public class TypeConversionUtil { return superType; } - private static boolean checkSuperTypesWithDifferentTypeArguments(PsiClassType.ClassResolveResult baseResult, - PsiClass derived, - PsiManager manager, - PsiSubstitutor derivedSubstitutor, + private static boolean checkSuperTypesWithDifferentTypeArguments(@NotNull PsiClassType.ClassResolveResult baseResult, + @NotNull PsiClass derived, + @NotNull PsiManager manager, + @NotNull PsiSubstitutor derivedSubstitutor, Set<PsiClass> visited, - final LanguageLevel languageLevel) { + @NotNull LanguageLevel languageLevel) { if (visited != null && visited.contains(derived)) return true; if (languageLevel.compareTo(LanguageLevel.JDK_1_5) < 0) return true; @@ -359,10 +358,12 @@ public class TypeConversionUtil { derivedSubstitutor = getSuperClassSubstitutor(derived, derived, derivedSubstitutor); return areSameArgumentTypes(derived, baseResult.getSubstitutor(), derivedSubstitutor, 1); } - else if (base.isInheritor(derived, true)) { - derivedSubstitutor = getSuperClassSubstitutor(derived, derived, derivedSubstitutor); - PsiSubstitutor baseSubstitutor = getSuperClassSubstitutor(derived, base, baseResult.getSubstitutor()); - if (!areSameArgumentTypes(derived, baseSubstitutor, derivedSubstitutor)) return false; + else { + PsiSubstitutor baseSubstitutor = getMaybeSuperClassSubstitutor(derived, base, baseResult.getSubstitutor(), null); + if (baseSubstitutor != null) { + derivedSubstitutor = getSuperClassSubstitutor(derived, derived, derivedSubstitutor); + if (!areSameArgumentTypes(derived, baseSubstitutor, derivedSubstitutor)) return false; + } } if (visited == null) visited = new THashSet<PsiClass>(); @@ -375,7 +376,7 @@ public class TypeConversionUtil { return true; } - private static boolean areSameParameterTypes(PsiClassType type1, PsiClassType type2) { + private static boolean areSameParameterTypes(@NotNull PsiClassType type1, @NotNull PsiClassType type2) { PsiClassType.ClassResolveResult resolveResult1 = type1.resolveGenerics(); PsiClassType.ClassResolveResult resolveResult2 = type2.resolveGenerics(); final PsiClass aClass = resolveResult1.getElement(); @@ -386,13 +387,13 @@ public class TypeConversionUtil { areSameArgumentTypes(aClass, resolveResult1.getSubstitutor(), resolveResult2.getSubstitutor()); } - private static boolean areSameArgumentTypes(PsiClass aClass, PsiSubstitutor substitutor1, PsiSubstitutor substitutor2) { + private static boolean areSameArgumentTypes(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor1, @NotNull PsiSubstitutor substitutor2) { return areSameArgumentTypes(aClass, substitutor1, substitutor2, 0); } - private static boolean areSameArgumentTypes(PsiClass aClass, - PsiSubstitutor substitutor1, - PsiSubstitutor substitutor2, + private static boolean areSameArgumentTypes(@NotNull PsiClass aClass, + @NotNull PsiSubstitutor substitutor1, + @NotNull PsiSubstitutor substitutor2, int level) { for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(aClass)) { PsiType typeArg1 = substitutor1.substitute(typeParameter); @@ -463,7 +464,7 @@ public class TypeConversionUtil { * STRING_TYPE for String, * Integer.MAX_VALUE for others */ - public static int getTypeRank(PsiType type) { + public static int getTypeRank(@NotNull PsiType type) { PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type); if (unboxedType != null) { type = unboxedType; @@ -597,13 +598,13 @@ public class TypeConversionUtil { return isPrimitiveAndNotNull(type); } - public static boolean isUnaryOperatorApplicable(PsiJavaToken token, PsiExpression operand) { + public static boolean isUnaryOperatorApplicable(@NotNull PsiJavaToken token, PsiExpression operand) { if (operand == null) return false; PsiType type = operand.getType(); return type != null && isUnaryOperatorApplicable(token, type); } - public static boolean isUnaryOperatorApplicable(final PsiJavaToken token, final PsiType type) { + public static boolean isUnaryOperatorApplicable(@NotNull PsiJavaToken token, @NotNull PsiType type) { IElementType i = token.getTokenType(); int typeRank = getTypeRank(type); if (i == JavaTokenType.MINUSMINUS || i == JavaTokenType.PLUSPLUS) { @@ -672,7 +673,7 @@ public class TypeConversionUtil { value = ((Number)rValue).longValue(); } else if (rValue instanceof Character) { - value = ((Character)rValue).charValue(); + value = (Character)rValue; } else { return false; @@ -832,7 +833,7 @@ public class TypeConversionUtil { return isClassAssignable(leftResult, rightResult, allowUncheckedConversion); } - private static boolean isAssignableFromWildcard(PsiType left, PsiWildcardType rightWildcardType) { + private static boolean isAssignableFromWildcard(@NotNull PsiType left, @NotNull PsiWildcardType rightWildcardType) { if (rightWildcardType.isSuper()) { final PsiClass aClass = PsiUtil.resolveClassInType(rightWildcardType.getSuperBound()); if (aClass instanceof PsiTypeParameter) { @@ -845,14 +846,14 @@ public class TypeConversionUtil { return isAssignable(left, rightWildcardType.getExtendsBound()); } - private static boolean isAssignableToWildcard(PsiWildcardType wildcardType, PsiType right) { + private static boolean isAssignableToWildcard(@NotNull PsiWildcardType wildcardType, @NotNull PsiType right) { if (wildcardType.isSuper()) { return isAssignable(wildcardType.getSuperBound(), right); } return isAssignable(wildcardType.getExtendsBound(), right); } - private static boolean isUnboxable(final PsiPrimitiveType left, final PsiClassType right) { + private static boolean isUnboxable(@NotNull PsiPrimitiveType left, @NotNull PsiClassType right) { final PsiPrimitiveType rightUnboxedType = PsiPrimitiveType.getUnboxedType(right); return rightUnboxedType != null && isAssignable(left, rightUnboxedType); } @@ -869,7 +870,7 @@ public class TypeConversionUtil { private static final Key<CachedValue<Set<String>>> POSSIBLE_BOXED_HOLDER_TYPES = Key.create("Types that may be possibly assigned from primitive ones"); - private static boolean isBoxable(final PsiClassType left, final PsiPrimitiveType right) { + private static boolean isBoxable(@NotNull PsiClassType left, @NotNull PsiPrimitiveType right) { if (!left.getLanguageLevel().isAtLeast(LanguageLevel.JDK_1_5)) return false; final PsiClass psiClass = left.resolve(); if (psiClass == null) return false; @@ -883,7 +884,8 @@ public class TypeConversionUtil { return rightBoxed != null && isAssignable(left, rightBoxed); } - private static Set<String> getAllBoxedTypeSupers(PsiClass psiClass) { + @NotNull + private static Set<String> getAllBoxedTypeSupers(@NotNull PsiClass psiClass) { PsiManager manager = psiClass.getManager(); final Project project = psiClass.getProject(); CachedValue<Set<String>> boxedHolderTypes = project.getUserData(POSSIBLE_BOXED_HOLDER_TYPES); @@ -908,12 +910,11 @@ public class TypeConversionUtil { }, false)); } - final Set<String> boxedHolders = boxedHolderTypes.getValue(); - return boxedHolders; + return boxedHolderTypes.getValue(); } - private static boolean isClassAssignable(PsiClassType.ClassResolveResult leftResult, - PsiClassType.ClassResolveResult rightResult, + private static boolean isClassAssignable(@NotNull PsiClassType.ClassResolveResult leftResult, + @NotNull PsiClassType.ClassResolveResult rightResult, boolean allowUncheckedConversion) { final PsiClass leftClass = leftResult.getElement(); final PsiClass rightClass = rightResult.getElement(); @@ -923,8 +924,8 @@ public class TypeConversionUtil { && typeParametersAgree(leftResult, rightResult, allowUncheckedConversion); } - private static boolean typeParametersAgree(PsiClassType.ClassResolveResult leftResult, - PsiClassType.ClassResolveResult rightResult, + private static boolean typeParametersAgree(@NotNull PsiClassType.ClassResolveResult leftResult, + @NotNull PsiClassType.ClassResolveResult rightResult, boolean allowUncheckedConversion) { PsiSubstitutor rightSubstitutor = rightResult.getSubstitutor(); PsiClass leftClass = leftResult.getElement(); @@ -962,7 +963,7 @@ public class TypeConversionUtil { private static final RecursionGuard ourGuard = RecursionManager.createGuard("isAssignable"); - public static boolean typesAgree(PsiType typeLeft, PsiType typeRight, final boolean allowUncheckedConversion) { + public static boolean typesAgree(@NotNull PsiType typeLeft, @NotNull PsiType typeRight, final boolean allowUncheckedConversion) { if (typeLeft instanceof PsiWildcardType) { final PsiWildcardType leftWildcard = (PsiWildcardType)typeLeft; final PsiType leftBound = leftWildcard.getBound(); @@ -986,7 +987,7 @@ public class TypeConversionUtil { return isAssignable(rightWildcard.getBound(), leftBound, allowUncheckedConversion); } }); - if (assignable != null && assignable.booleanValue()) { + if (assignable != null && assignable) { return true; } } @@ -1022,7 +1023,7 @@ public class TypeConversionUtil { @Nullable public static PsiSubstitutor getClassSubstitutor(@NotNull PsiClass superClassCandidate, @NotNull PsiClass derivedClassCandidate, - PsiSubstitutor derivedSubstitutor) { + @NotNull PsiSubstitutor derivedSubstitutor) { if (superClassCandidate.getManager().areElementsEquivalent(superClassCandidate, derivedClassCandidate)) { PsiTypeParameter[] baseParams = superClassCandidate.getTypeParameters(); PsiTypeParameter[] derivedParams = derivedClassCandidate.getTypeParameters(); @@ -1031,8 +1032,7 @@ public class TypeConversionUtil { } return derivedSubstitutor; } - if (!derivedClassCandidate.isInheritor(superClassCandidate, true)) return null; - return getSuperClassSubstitutor(superClassCandidate, derivedClassCandidate, derivedSubstitutor); + return getMaybeSuperClassSubstitutor(superClassCandidate, derivedClassCandidate, derivedSubstitutor, null); } private static final Set<String> ourReportedSuperClassSubstitutorExceptions = new ConcurrentHashSet<String>(); @@ -1042,52 +1042,61 @@ public class TypeConversionUtil { * values that they have in <code>derivedClass</code>, given that type parameters in * <code>derivedClass</code> are bound by <code>derivedSubstitutor</code>. * <code>superClass</code> must be a super class/interface of <code>derivedClass</code> (as in - * <code>InheritanceUtil.isInheritor(derivedClass, superClass, true)</code> + * <code>InheritanceUtil.isInheritorOrSelf(derivedClass, superClass, true)</code> * * @return substitutor (never returns <code>null</code>) * @see PsiClass#isInheritor(PsiClass, boolean) + * @see InheritanceUtil#isInheritorOrSelf(com.intellij.psi.PsiClass, com.intellij.psi.PsiClass, boolean) */ @NotNull public static PsiSubstitutor getSuperClassSubstitutor(@NotNull PsiClass superClass, @NotNull PsiClass derivedClass, @NotNull PsiSubstitutor derivedSubstitutor) { - // [dsl] assertion commented out since we no longer cache isInheritor - //LOG.assertTrue(derivedClass.isInheritor(superClass, true), "Not inheritor: " + derivedClass + " super: " + superClass); + if (!superClass.hasTypeParameters() && superClass.getContainingClass() == null) return PsiSubstitutor.EMPTY; //optimization and protection against EJB queer hierarchy + + Set<PsiClass> visited = new THashSet<PsiClass>(); + PsiSubstitutor substitutor = getMaybeSuperClassSubstitutor(superClass, derivedClass, derivedSubstitutor, visited); + + if (substitutor == null) { + if (ourReportedSuperClassSubstitutorExceptions.add(derivedClass.getQualifiedName() + "/" + superClass.getQualifiedName())) { + reportHierarchyInconsistency(superClass, derivedClass, visited); + } + return PsiSubstitutor.EMPTY; + } + return substitutor; + } - if (!superClass.hasTypeParameters() && superClass.getContainingClass() == null) return PsiSubstitutor.EMPTY; //optimization + // the same as getSuperClassSubstitutor() but can return null, which means that classes were not inheritors + @Nullable + public static PsiSubstitutor getMaybeSuperClassSubstitutor(@NotNull PsiClass superClass, + @NotNull PsiClass derivedClass, + @NotNull PsiSubstitutor derivedSubstitutor, + @Nullable Set<PsiClass> visited) { + if (!superClass.hasTypeParameters() && superClass.getContainingClass() == null) { + return InheritanceUtil.isInheritorOrSelf(derivedClass, superClass, true) ? PsiSubstitutor.EMPTY : null; //optimization + } final PsiManager manager = superClass.getManager(); if (PsiUtil.isRawSubstitutor(derivedClass, derivedSubstitutor)) { - return JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createRawSubstitutor(superClass); + return InheritanceUtil.isInheritorOrSelf(derivedClass, superClass, true) ? JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createRawSubstitutor(superClass) : null; } - final PsiClass objectClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(CommonClassNames.JAVA_LANG_OBJECT, superClass.getResolveScope()); - if (manager.areElementsEquivalent(superClass, objectClass)) { + if (CommonClassNames.JAVA_LANG_OBJECT_SHORT.equals(superClass.getName()) && + manager.areElementsEquivalent(superClass, JavaPsiFacade.getInstance(manager.getProject()).findClass(CommonClassNames.JAVA_LANG_OBJECT, superClass.getResolveScope()))) { return PsiSubstitutor.EMPTY; } - PsiSubstitutor substitutor; - final Set<PsiClass> visited = new THashSet<PsiClass>(); if (derivedClass instanceof PsiAnonymousClass) { final PsiClassType baseType = ((PsiAnonymousClass)derivedClass).getBaseClassType(); final JavaResolveResult result = baseType.resolveGenerics(); if (result.getElement() == null) return PsiSubstitutor.UNKNOWN; - substitutor = getSuperClassSubstitutorInner(superClass, (PsiClass)result.getElement(), - derivedSubstitutor.putAll(result.getSubstitutor()), visited, manager); - } - else { - substitutor = getSuperClassSubstitutorInner(superClass, derivedClass, derivedSubstitutor, visited, manager); + derivedClass = (PsiClass)result.getElement(); + derivedSubstitutor = derivedSubstitutor.putAll(result.getSubstitutor()); } - if (substitutor == null) { - if (ourReportedSuperClassSubstitutorExceptions.add(derivedClass.getQualifiedName() + "/" + superClass.getQualifiedName())) { - reportHierarchyInconsistency(superClass, derivedClass, visited); - } - return PsiSubstitutor.EMPTY; - } - return substitutor; + return getSuperClassSubstitutorInner(superClass, derivedClass, derivedSubstitutor, visited == null ? new THashSet<PsiClass>() : visited, manager); } - private static void reportHierarchyInconsistency(PsiClass superClass, PsiClass derivedClass, Set<PsiClass> visited) { + private static void reportHierarchyInconsistency(@NotNull PsiClass superClass, @NotNull PsiClass derivedClass, @NotNull Set<PsiClass> visited) { final StringBuilder msg = new StringBuilder("Super: " + classInfo(superClass)); msg.append("visited:\n"); for (PsiClass aClass : visited) { @@ -1105,7 +1114,8 @@ public class TypeConversionUtil { LOG.error(msg.toString()); } - private static String classInfo(PsiClass aClass) { + @NotNull + private static String classInfo(@NotNull PsiClass aClass) { String s = aClass.getQualifiedName() + "(" + aClass.getClass().getName() + "; " + PsiUtilCore.getVirtualFile(aClass) + ");\n"; s += "extends: "; for (PsiClassType type : aClass.getExtendsListTypes()) { @@ -1124,12 +1134,14 @@ public class TypeConversionUtil { return getSuperClassSubstitutor(superClass, classResolveResult.getElement(), classResolveResult.getSubstitutor()); } - private static PsiSubstitutor getSuperClassSubstitutorInner(PsiClass base, - PsiClass candidate, - PsiSubstitutor candidateSubstitutor, - Set<PsiClass> visited, - PsiManager manager) { + @Nullable + private static PsiSubstitutor getSuperClassSubstitutorInner(@NotNull PsiClass base, + @NotNull PsiClass candidate, + @NotNull PsiSubstitutor candidateSubstitutor, + @NotNull Set<PsiClass> visited, + @NotNull PsiManager manager) { if (!visited.add(candidate)) return null; + assert candidateSubstitutor.isValid(); if (base == candidate) return candidateSubstitutor; if (manager.areElementsEquivalent(base, candidate)) { @@ -1148,19 +1160,18 @@ public class TypeConversionUtil { } } - PsiSubstitutor substitutor = checkReferenceList(candidate.getExtendsListTypes(), candidateSubstitutor, base, visited, - manager); + PsiSubstitutor substitutor = checkReferenceList(candidate.getExtendsListTypes(), candidateSubstitutor, base, visited, manager); if (substitutor == null) { substitutor = checkReferenceList(candidate.getImplementsListTypes(), candidateSubstitutor, base, visited, manager); } return substitutor; } - private static PsiSubstitutor checkReferenceList(final PsiClassType[] types, PsiSubstitutor candidateSubstitutor, - PsiClass base, - Set<PsiClass> set, - PsiManager manager) { - assert candidateSubstitutor.isValid(); + private static PsiSubstitutor checkReferenceList(@NotNull PsiClassType[] types, + @NotNull PsiSubstitutor candidateSubstitutor, + @NotNull PsiClass base, + @NotNull Set<PsiClass> set, + @NotNull PsiManager manager) { for (final PsiClassType type : types) { final PsiType substitutedType = candidateSubstitutor.substitute(type); //if (!(substitutedType instanceof PsiClassType)) return null; @@ -1170,8 +1181,7 @@ public class TypeConversionUtil { final PsiElement newCandidate = result.getElement(); if (newCandidate != null) { final PsiSubstitutor substitutor = result.getSubstitutor(); - final PsiSubstitutor newSubstitutor = getSuperClassSubstitutorInner(base, (PsiClass)newCandidate, - substitutor, set, manager); + final PsiSubstitutor newSubstitutor = getSuperClassSubstitutorInner(base, (PsiClass)newCandidate, substitutor, set, manager); if (newSubstitutor != null) { return type.isRaw() ? JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createRawSubstitutor(base) : newSubstitutor; } @@ -1183,6 +1193,7 @@ public class TypeConversionUtil { /** * see JLS 5.6.2 */ + @NotNull public static PsiType binaryNumericPromotion(PsiType type1, PsiType type2) { if (isDoubleType(type1)) return unbox(type1); if (isDoubleType(type2)) return unbox(type2); @@ -1194,7 +1205,8 @@ public class TypeConversionUtil { return PsiType.INT; } - private static PsiType unbox(PsiType type) { + @NotNull + private static PsiType unbox(@NotNull PsiType type) { if (type instanceof PsiPrimitiveType) return type; if (type instanceof PsiClassType) { type = PsiPrimitiveType.getUnboxedType(type); @@ -1393,6 +1405,7 @@ public class TypeConversionUtil { return value; } + @NotNull public static PsiType unboxAndBalanceTypes(PsiType type1, PsiType type2) { if (type1 instanceof PsiClassType) type1 = PsiPrimitiveType.getUnboxedType(type1); if (type2 instanceof PsiClassType) type2 = PsiPrimitiveType.getUnboxedType(type2); @@ -1442,7 +1455,7 @@ public class TypeConversionUtil { } @Nullable - public static PsiType calcTypeForBinaryExpression(PsiType lType, PsiType rType, IElementType sign, boolean accessLType) { + public static PsiType calcTypeForBinaryExpression(PsiType lType, PsiType rType, @NotNull IElementType sign, boolean accessLType) { if (sign == JavaTokenType.PLUS) { // evaluate right argument first, since '+-/*%' is left associative and left operand tends to be bigger if (rType == null) return null; @@ -1512,321 +1525,371 @@ public class TypeConversionUtil { } private interface Caster { - Object cast(Object operand); + @NotNull + Object cast(@NotNull Object operand); } private static final Caster[][] caster = { { new Caster() { + @NotNull @Override - public Object cast(Object operand) { + public Object cast(@NotNull Object operand) { return operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Short.valueOf((short)((Number)operand).intValue()); + public Object cast(@NotNull Object operand) { + return (short)((Number)operand).intValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Character((char) ((Number) operand).intValue()); + public Object cast(@NotNull Object operand) { + return (char)((Number)operand).intValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Integer.valueOf(((Number)operand).intValue()); + public Object cast(@NotNull Object operand) { + return ((Number)operand).intValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Long.valueOf(((Number)operand).intValue()); + public Object cast(@NotNull Object operand) { + return (long)((Number)operand).intValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Float(((Number) operand).intValue()); + public Object cast(@NotNull Object operand) { + return (float)((Number)operand).intValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Double(((Number) operand).intValue()); + public Object cast(@NotNull Object operand) { + return (double)((Number)operand).intValue(); } } } , { new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Byte.valueOf((byte)((Short)operand).shortValue()); + public Object cast(@NotNull Object operand) { + return (byte)((Short)operand).shortValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Short.valueOf(((Short)operand).shortValue()); + public Object cast(@NotNull Object operand) { + return operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Character((char) ((Short) operand).shortValue()); + public Object cast(@NotNull Object operand) { + return (char)((Short)operand).shortValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Integer.valueOf(((Short)operand).shortValue()); + public Object cast(@NotNull Object operand) { + return (int)(Short)operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Long.valueOf(((Short)operand).shortValue()); + public Object cast(@NotNull Object operand) { + return (long)(Short)operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Float(((Short) operand).shortValue()); + public Object cast(@NotNull Object operand) { + return (float)(Short)operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Double(((Short) operand).shortValue()); + public Object cast(@NotNull Object operand) { + return (double)(Short)operand; } } } , { new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Byte.valueOf((byte)((Character)operand).charValue()); + public Object cast(@NotNull Object operand) { + return (byte)((Character)operand).charValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Short.valueOf((short)((Character)operand).charValue()); + public Object cast(@NotNull Object operand) { + return (short)((Character)operand).charValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Character(((Character) operand).charValue()); + public Object cast(@NotNull Object operand) { + return operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Integer.valueOf(((Character)operand).charValue()); + public Object cast(@NotNull Object operand) { + return (int)(Character)operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Long.valueOf(((Character)operand).charValue()); + public Object cast(@NotNull Object operand) { + return (long)(Character)operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Float(((Character) operand).charValue()); + public Object cast(@NotNull Object operand) { + return (float)(Character)operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Double(((Character) operand).charValue()); + public Object cast(@NotNull Object operand) { + return (double)(Character)operand; } } } , { new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Byte.valueOf((byte)((Integer)operand).intValue()); + public Object cast(@NotNull Object operand) { + return (byte)((Integer)operand).intValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Short.valueOf((short)((Integer)operand).intValue()); + public Object cast(@NotNull Object operand) { + return (short)((Integer)operand).intValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Character((char) ((Integer) operand).intValue()); + public Object cast(@NotNull Object operand) { + return (char)((Integer)operand).intValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Integer.valueOf(((Integer)operand).intValue()); + public Object cast(@NotNull Object operand) { + return operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Long.valueOf(((Integer)operand).intValue()); + public Object cast(@NotNull Object operand) { + return (long)(Integer)operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Float(((Integer) operand).intValue()); + public Object cast(@NotNull Object operand) { + return (float)(Integer)operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Double(((Integer) operand).intValue()); + public Object cast(@NotNull Object operand) { + return (double)(Integer)operand; } } } , { new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Byte.valueOf((byte)((Long)operand).longValue()); + public Object cast(@NotNull Object operand) { + return (byte)((Long)operand).longValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Short.valueOf((short)((Long)operand).longValue()); + public Object cast(@NotNull Object operand) { + return (short)((Long)operand).longValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Character((char) ((Long) operand).longValue()); + public Object cast(@NotNull Object operand) { + return (char)((Long)operand).longValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Integer.valueOf((int)((Long)operand).longValue()); + public Object cast(@NotNull Object operand) { + return (int)((Long)operand).longValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Long.valueOf(((Long)operand).longValue()); + public Object cast(@NotNull Object operand) { + return operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Float(((Long) operand).longValue()); + public Object cast(@NotNull Object operand) { + return (float)(Long)operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Double(((Long) operand).longValue()); + public Object cast(@NotNull Object operand) { + return (double)(Long)operand; } } } , { new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Byte.valueOf((byte)((Float)operand).floatValue()); + public Object cast(@NotNull Object operand) { + return (byte)((Float)operand).floatValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Short.valueOf((short)((Float)operand).floatValue()); + public Object cast(@NotNull Object operand) { + return (short)((Float)operand).floatValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Character((char) ((Float) operand).floatValue()); + public Object cast(@NotNull Object operand) { + return (char)((Float)operand).floatValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Integer.valueOf((int)((Float)operand).floatValue()); + public Object cast(@NotNull Object operand) { + return (int)((Float)operand).floatValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Long.valueOf((long)((Float)operand).floatValue()); + public Object cast(@NotNull Object operand) { + return (long)((Float)operand).floatValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Float(((Float) operand).floatValue()); + public Object cast(@NotNull Object operand) { + return operand; } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Double(((Float) operand).floatValue()); + public Object cast(@NotNull Object operand) { + return (double)(Float)operand; } } } , { new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Byte.valueOf((byte)((Double)operand).doubleValue()); + public Object cast(@NotNull Object operand) { + return (byte)((Double)operand).doubleValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Short.valueOf((short)((Double)operand).doubleValue()); + public Object cast(@NotNull Object operand) { + return (short)((Double)operand).doubleValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Character((char) ((Double) operand).doubleValue()); + public Object cast(@NotNull Object operand) { + return (char)((Double)operand).doubleValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Integer.valueOf((int)((Double)operand).doubleValue()); + public Object cast(@NotNull Object operand) { + return (int)((Double)operand).doubleValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return Long.valueOf((long)((Double)operand).doubleValue()); + public Object cast(@NotNull Object operand) { + return (long)((Double)operand).doubleValue(); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Float(((Double) operand).doubleValue()); + public Object cast(@NotNull Object operand) { + return new Float((Double)operand); } } , new Caster() { + @NotNull @Override - public Object cast(Object operand) { - return new Double(((Double) operand).doubleValue()); + public Object cast(@NotNull Object operand) { + return operand; } } } @@ -1844,7 +1907,7 @@ public class TypeConversionUtil { WRAPPER_TO_PRIMITIVE.put(Double.class, PsiType.DOUBLE); } - private static PsiType wrapperToPrimitive(Object o) { + private static PsiType wrapperToPrimitive(@NotNull Object o) { return WRAPPER_TO_PRIMITIVE.get(o.getClass()); } diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/CustomExceptionHandler.java b/java/java-psi-impl/src/com/intellij/codeInsight/CustomExceptionHandler.java new file mode 100644 index 000000000000..7678390d0356 --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/codeInsight/CustomExceptionHandler.java @@ -0,0 +1,13 @@ +package com.intellij.codeInsight; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiClassType; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class CustomExceptionHandler { + public static final ExtensionPointName<CustomExceptionHandler> KEY = ExtensionPointName.create("com.intellij.custom.exception.handler"); + + public abstract boolean isHandled(@Nullable PsiElement element, @NotNull PsiClassType exceptionType, PsiElement topElement); +} diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java b/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java index 552c7e2d9ff5..bb4e322a2eec 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.controlFlow.*; @@ -675,6 +676,10 @@ public class ExceptionUtil { // exceptions thrown in field initializers should be thrown in all class constructors return areAllConstructorsThrow(aClass, exceptionType); } + } else { + for (CustomExceptionHandler exceptionHandler : Extensions.getExtensions(CustomExceptionHandler.KEY)) { + if (exceptionHandler.isHandled(element, exceptionType, topElement)) return true; + } } return isHandled(parent, exceptionType, topElement); } diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java index 5e008afb4797..e2de5a55e0b3 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java @@ -598,9 +598,15 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem Document document = method.getContainingFile().getViewProvider().getDocument(); PsiCodeBlock body = method.getBody(); - if (body == null || document == null) { + PsiIdentifier nameIdentifier = method.getNameIdentifier(); + if (body == null || document == null || nameIdentifier == null) { return false; } + if (document.getLineNumber(nameIdentifier.getTextRange().getStartOffset()) != + document.getLineNumber(method.getParameterList().getTextRange().getEndOffset())) { + return false; + } + PsiJavaToken lBrace = body.getLBrace(); PsiJavaToken rBrace = body.getRBrace(); PsiStatement[] statements = body.getStatements(); diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ParameterNameFoldingManager.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ParameterNameFoldingManager.java index aca4357f7e49..a8b2b40111ba 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ParameterNameFoldingManager.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ParameterNameFoldingManager.java @@ -39,7 +39,8 @@ public class ParameterNameFoldingManager { Couple.of("first", "last"), Couple.of("first", "second"), Couple.of("from", "to"), - Couple.of("key", "value") + Couple.of("key", "value"), + Couple.of("min", "max") ); private final PsiCallExpression myCallExpression; @@ -58,7 +59,8 @@ public class ParameterNameFoldingManager { if (callArgument instanceof PsiPrefixExpression) { PsiPrefixExpression expr = (PsiPrefixExpression)callArgument; IElementType tokenType = expr.getOperationTokenType(); - return JavaTokenType.MINUS.equals(tokenType) && expr.getOperand() instanceof PsiLiteralExpression; + return (JavaTokenType.MINUS.equals(tokenType) + || JavaTokenType.PLUS.equals(tokenType)) && expr.getOperand() instanceof PsiLiteralExpression; } return false; diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/ColorUtil.java b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/ColorUtil.java index f7094421b980..ac2fe33d0e43 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/ColorUtil.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/ColorUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -17,10 +17,10 @@ package com.intellij.codeInsight.javadoc; import com.intellij.psi.*; import com.intellij.util.ArrayUtil; +import com.intellij.util.ReflectionUtil; import org.jetbrains.annotations.NotNull; import java.awt.*; -import java.lang.reflect.Field; /** * @author spleaner @@ -98,14 +98,12 @@ public class ColorUtil { if (reference != null) { final PsiElement psiElement = reference.resolve(); if (psiElement instanceof PsiField) { - final PsiClass psiClass = ((PsiField) psiElement).getContainingClass(); + PsiField psiField = (PsiField)psiElement; + final PsiClass psiClass = psiField.getContainingClass(); if (psiClass != null && "java.awt.Color".equals(psiClass.getQualifiedName())) { - try { - Field field = Class.forName("java.awt.Color").getField(((PsiField)psiElement).getName()); - final Color c = (Color) field.get(null); + Color c = ReflectionUtil.getField(Color.class, null, Color.class, psiField.getName()); + if (c != null) { buffer.append(generatePreviewHtml(c)); - } catch (Exception e) { - // nothing } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java b/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java index e1116894f14f..5f3eee5c6be3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java @@ -34,6 +34,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.VisibilityUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -253,8 +254,9 @@ public class PsiDiamondTypeImpl extends PsiDiamondType { PsiTypeParameter[] params, PsiJavaCodeReferenceElement reference) { final StringBuilder buf = new StringBuilder(); - buf.append(constructor != null ? constructor.getModifierList().getText() : containingClass.getModifierList().getText()); - if (buf.length() > 0) { + final String modifier = VisibilityUtil.getVisibilityModifier(constructor != null ? constructor.getModifierList() : containingClass.getModifierList()); + if (!PsiModifier.PACKAGE_LOCAL.equals(modifier)) { + buf.append(modifier); buf.append(" "); } buf.append("static "); @@ -262,8 +264,20 @@ public class PsiDiamondTypeImpl extends PsiDiamondType { buf.append(StringUtil.join(params, new Function<PsiTypeParameter, String>() { @Override public String fun(PsiTypeParameter psiTypeParameter) { - final String extendsList = psiTypeParameter.getLanguage().isKindOf(JavaLanguage.INSTANCE) ? psiTypeParameter.getExtendsList().getText() : null; - return psiTypeParameter.getName() + (StringUtil.isEmpty(extendsList) ? "" : " " + extendsList); + String extendsList = ""; + if (psiTypeParameter.getLanguage().isKindOf(JavaLanguage.INSTANCE)) { + final PsiClassType[] extendsListTypes = psiTypeParameter.getExtendsListTypes(); + if (extendsListTypes.length > 0) { + final Function<PsiClassType, String> canonicalTypePresentationFun = new Function<PsiClassType, String>() { + @Override + public String fun(PsiClassType type) { + return type.getCanonicalText(); + } + }; + extendsList = " extends " + StringUtil.join(extendsListTypes, canonicalTypePresentationFun, "&"); + } + } + return psiTypeParameter.getName() + extendsList; } }, ", ")); buf.append(">"); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/InheritanceImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/InheritanceImplUtil.java index f958555a3c45..9427551aacf8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/InheritanceImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/InheritanceImplUtil.java @@ -25,9 +25,7 @@ import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.containers.ConcurrentWeakHashMap; -import com.intellij.util.containers.HashSet; import gnu.trove.THashSet; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,10 +37,12 @@ public class InheritanceImplUtil { public static boolean isInheritor(@NotNull final PsiClass candidateClass, @NotNull PsiClass baseClass, final boolean checkDeep) { if (baseClass instanceof PsiAnonymousClass) return false; - if (!checkDeep) return isInheritor(candidateClass, baseClass, false, null); + if (!checkDeep) { + return isInheritor(candidateClass.getManager(), candidateClass, baseClass, false, null); + } - if (CommonClassNames.JAVA_LANG_OBJECT_SHORT.equals(candidateClass.getName()) && CommonClassNames.JAVA_LANG_OBJECT.equals(candidateClass.getQualifiedName())) return false; - if (CommonClassNames.JAVA_LANG_OBJECT_SHORT.equals(baseClass.getName()) && CommonClassNames.JAVA_LANG_OBJECT.equals(baseClass.getQualifiedName())) return true; + if (hasObjectQualifiedName(candidateClass)) return false; + if (hasObjectQualifiedName(baseClass)) return true; Map<PsiClass, Boolean> map = CachedValuesManager. getCachedValue(candidateClass, new CachedValueProvider<Map<PsiClass, Boolean>>() { @Nullable @@ -55,18 +55,29 @@ public class InheritanceImplUtil { Boolean computed = map.get(baseClass); if (computed == null) { - computed = isInheritor(candidateClass, baseClass, true, null); + computed = isInheritor(candidateClass.getManager(), candidateClass, baseClass, true, null); map.put(baseClass, computed); } return computed; } - private static boolean isInheritor(@NotNull PsiClass candidateClass, @NotNull PsiClass baseClass, boolean checkDeep, Set<PsiClass> checkedClasses) { + public static boolean hasObjectQualifiedName(@NotNull PsiClass candidateClass) { + if (!CommonClassNames.JAVA_LANG_OBJECT_SHORT.equals(candidateClass.getName())) { + return false; + } + PsiElement parent = candidateClass.getParent(); + return parent instanceof PsiJavaFile && CommonClassNames.DEFAULT_PACKAGE.equals(((PsiJavaFile)parent).getPackageName()); + } + + private static boolean isInheritor(@NotNull PsiManager manager, + @NotNull PsiClass candidateClass, + @NotNull PsiClass baseClass, + boolean checkDeep, + @Nullable Set<PsiClass> checkedClasses) { if (candidateClass instanceof PsiAnonymousClass) { final PsiClass baseCandidateClass = ((PsiAnonymousClass)candidateClass).getBaseClassType().resolve(); return baseCandidateClass != null && InheritanceUtil.isInheritorOrSelf(baseCandidateClass, baseClass, checkDeep); } - PsiManager manager = candidateClass.getManager(); /* //TODO fix classhashprovider so it doesn't use class qnames only final ClassHashProvider provider = getHashProvider((PsiManagerImpl) manager); if (checkDeep && provider != null) { @@ -81,8 +92,7 @@ public class InheritanceImplUtil { LOG.debug("Using uncached version for " + candidateClass.getQualifiedName() + " and " + baseClass); } - @NonNls final String baseName = baseClass.getName(); - if (CommonClassNames.JAVA_LANG_OBJECT_SHORT.equals(baseName)) { + if (hasObjectQualifiedName(baseClass)) { PsiClass objectClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(CommonClassNames.JAVA_LANG_OBJECT, candidateClass.getResolveScope()); if (manager.areElementsEquivalent(baseClass, objectClass)) { if (manager.areElementsEquivalent(candidateClass, objectClass)) return false; @@ -103,6 +113,7 @@ public class InheritanceImplUtil { if (cInt == bInt && checkReferenceListWithQualifiedNames(baseQName, candidateClass.getExtendsList(), manager, scope)) return true; return bInt && !cInt && checkReferenceListWithQualifiedNames(baseQName, candidateClass.getImplementsList(), manager, scope); } + String baseName = baseClass.getName(); if (cInt == bInt) { for (PsiClassType type : candidateClass.getExtendsListTypes()) { if (Comparing.equal(type.getClassName(), baseName)) { @@ -125,7 +136,7 @@ public class InheritanceImplUtil { return false; } - return isInheritorWithoutCaching(candidateClass, baseClass, checkDeep, checkedClasses); + return isInheritorWithoutCaching(manager, candidateClass, baseClass, checkedClasses); } private static boolean checkReferenceListWithQualifiedNames(final String baseQName, final PsiReferenceList extList, final PsiManager manager, @@ -141,63 +152,50 @@ public class InheritanceImplUtil { return false; } - private static boolean isInheritorWithoutCaching(PsiClass aClass, PsiClass baseClass, boolean checkDeep, Set<PsiClass> checkedClasses) { - PsiManager manager = aClass.getManager(); + private static boolean isInheritorWithoutCaching(@NotNull PsiManager manager, + @NotNull PsiClass aClass, + @NotNull PsiClass baseClass, + @Nullable Set<PsiClass> checkedClasses) { if (manager.areElementsEquivalent(aClass, baseClass)) return false; if (aClass.isInterface() && !baseClass.isInterface()) { return false; } - //if (PsiUtil.hasModifierProperty(baseClass, PsiModifier.FINAL)) { - // return false; - //} - - if (checkDeep) { - if (checkedClasses == null) { - checkedClasses = new THashSet<PsiClass>(); - } - checkedClasses.add(aClass); + if (checkedClasses == null) { + checkedClasses = new THashSet<PsiClass>(); } + checkedClasses.add(aClass); - if (!aClass.isInterface() && baseClass.isInterface()) { - if (checkDeep && checkInheritor(aClass.getSuperClass(), baseClass, checkDeep, checkedClasses)) { - return true; - } - return checkInheritor(aClass.getInterfaces(), baseClass, checkDeep, checkedClasses); - - } - else { - return checkInheritor(aClass.getSupers(), baseClass, checkDeep, checkedClasses); - } + return checkInheritor(manager, aClass.getExtendsListTypes(), baseClass, checkedClasses) || + checkInheritor(manager, aClass.getImplementsListTypes(), baseClass, checkedClasses); } - private static boolean checkInheritor(PsiClass[] supers, PsiClass baseClass, boolean checkDeep, Set<PsiClass> checkedClasses) { - for (PsiClass aSuper : supers) { - if (checkInheritor(aSuper, baseClass, checkDeep, checkedClasses)) { + private static boolean checkInheritor(@NotNull PsiManager manager, + @NotNull PsiClassType[] supers, + @NotNull PsiClass baseClass, + @NotNull Set<PsiClass> checkedClasses) { + for (PsiClassType aSuper : supers) { + PsiClass aClass = aSuper.resolve(); + if (aClass != null && checkInheritor(manager, aClass, baseClass, checkedClasses)) { return true; } } return false; } - private static boolean checkInheritor(PsiClass aClass, PsiClass baseClass, boolean checkDeep, Set<PsiClass> checkedClasses) { + private static boolean checkInheritor(@NotNull PsiManager manager, + @NotNull PsiClass aClass, + @NotNull PsiClass baseClass, + @NotNull Set<PsiClass> checkedClasses) { ProgressIndicatorProvider.checkCanceled(); - if (aClass != null) { - PsiManager manager = baseClass.getManager(); - if (manager.areElementsEquivalent(baseClass, aClass)) { - return true; - } - if (checkedClasses != null && checkedClasses.contains(aClass)) { // to prevent infinite recursion - return false; - } - if (checkDeep) { - if (isInheritor(aClass, baseClass, checkDeep, checkedClasses)) { - return true; - } - } + if (manager.areElementsEquivalent(baseClass, aClass)) { + return true; } - return false; + if (checkedClasses.contains(aClass)) { // to prevent infinite recursion + return false; + } + return isInheritor(manager, aClass, baseClass, true, checkedClasses); } public static boolean isInheritorDeep(@NotNull PsiClass candidateClass, @NotNull PsiClass baseClass, @Nullable final PsiClass classToByPass) { @@ -207,9 +205,9 @@ public class InheritanceImplUtil { Set<PsiClass> checkedClasses = null; if (classToByPass != null) { - checkedClasses = new HashSet<PsiClass>(); + checkedClasses = new THashSet<PsiClass>(); checkedClasses.add(classToByPass); } - return isInheritor(candidateClass, baseClass, true, checkedClasses); + return isInheritor(candidateClass.getManager(), candidateClass, baseClass, true, checkedClasses); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java index 514087492300..938b40f51bb8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl; +import com.intellij.codeInsight.AnnotationTargetUtil; import com.intellij.lang.ASTNode; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -51,7 +52,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Set; @@ -60,22 +60,6 @@ import static com.intellij.psi.PsiAnnotation.TargetType; public class PsiImplUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiImplUtil"); - private static final Set<TargetType> DEFAULT_TARGETS = Collections.unmodifiableSet(ContainerUtil.newHashSet( - TargetType.PACKAGE, TargetType.TYPE, TargetType.ANNOTATION_TYPE, - TargetType.FIELD, TargetType.METHOD, TargetType.CONSTRUCTOR, - TargetType.PARAMETER, TargetType.LOCAL_VARIABLE)); - - private static final TargetType[] PACKAGE_TARGETS = {TargetType.PACKAGE}; - private static final TargetType[] TYPE_USE_TARGETS = {TargetType.TYPE_USE}; - private static final TargetType[] ANNOTATION_TARGETS = {TargetType.ANNOTATION_TYPE, TargetType.TYPE, TargetType.TYPE_USE}; - private static final TargetType[] TYPE_TARGETS = {TargetType.TYPE, TargetType.TYPE_USE}; - private static final TargetType[] TYPE_PARAMETER_TARGETS = {TargetType.TYPE_PARAMETER, TargetType.TYPE_USE}; - private static final TargetType[] CONSTRUCTOR_TARGETS = {TargetType.CONSTRUCTOR, TargetType.TYPE_USE}; - private static final TargetType[] METHOD_TARGETS = {TargetType.METHOD, TargetType.TYPE_USE}; - private static final TargetType[] FIELD_TARGETS = {TargetType.FIELD, TargetType.TYPE_USE}; - private static final TargetType[] PARAMETER_TARGETS = {TargetType.PARAMETER, TargetType.TYPE_USE}; - private static final TargetType[] LOCAL_VARIABLE_TARGETS ={TargetType.LOCAL_VARIABLE, TargetType.TYPE_USE}; - private PsiImplUtil() { } @NotNull @@ -376,93 +360,14 @@ public class PsiImplUtil { PsiModifierList modifierList = annotationType.getModifierList(); if (modifierList == null) return null; PsiAnnotation target = modifierList.findAnnotation(CommonClassNames.JAVA_LANG_ANNOTATION_TARGET); - if (target == null) return DEFAULT_TARGETS; // if omitted it is applicable to all but Java 8 TYPE_USE/TYPE_PARAMETERS targets - - PsiAnnotationMemberValue value = target.findAttributeValue(null); - if (value instanceof PsiReference) { - TargetType targetType = translateTargetRef((PsiReference)value); - if (targetType != null) { - return Collections.singleton(targetType); - } - } - else if (value instanceof PsiArrayInitializerMemberValue) { - Set <TargetType> targets = ContainerUtil.newHashSet(); - for (PsiAnnotationMemberValue initializer : ((PsiArrayInitializerMemberValue)value).getInitializers()) { - if (initializer instanceof PsiReference) { - TargetType targetType = translateTargetRef((PsiReference)initializer); - if (targetType != null) { - targets.add(targetType); - } - } - } - return targets; - } + if (target == null) return AnnotationTargetUtil.DEFAULT_TARGETS; // if omitted it is applicable to all but Java 8 TYPE_USE/TYPE_PARAMETERS targets - return null; - } - - @Nullable - private static TargetType translateTargetRef(PsiReference reference) { - PsiElement field = reference.resolve(); - if (field instanceof PsiEnumConstant) { - String name = ((PsiEnumConstant)field).getName(); - try { - return TargetType.valueOf(name); - } - catch (IllegalArgumentException e) { - LOG.warn("Unknown target: " + name); - } - } - return null; + return AnnotationTargetUtil.extractRequiredAnnotationTargets(target.findAttributeValue(null)); } @NotNull public static TargetType[] getTargetsForLocation(@Nullable PsiAnnotationOwner owner) { - if (owner == null) { - return TargetType.EMPTY_ARRAY; - } - - if (owner instanceof PsiType || owner instanceof PsiTypeElement) { - return TYPE_USE_TARGETS; - } - - if (owner instanceof PsiTypeParameter) { - return TYPE_PARAMETER_TARGETS; - } - - if (owner instanceof PsiModifierList) { - PsiElement element = ((PsiModifierList)owner).getParent(); - if (element instanceof PsiPackageStatement) { - return PACKAGE_TARGETS; - } - if (element instanceof PsiClass) { - if (((PsiClass)element).isAnnotationType()) { - return ANNOTATION_TARGETS; - } - else { - return TYPE_TARGETS; - } - } - if (element instanceof PsiMethod) { - if (((PsiMethod)element).isConstructor()) { - return CONSTRUCTOR_TARGETS; - } - else { - return METHOD_TARGETS; - } - } - if (element instanceof PsiField) { - return FIELD_TARGETS; - } - if (element instanceof PsiParameter) { - return PARAMETER_TARGETS; - } - if (element instanceof PsiLocalVariable) { - return LOCAL_VARIABLE_TARGETS; - } - } - - return TargetType.EMPTY_ARRAY; + return AnnotationTargetUtil.getTargetsForLocation(owner); } @Nullable @@ -782,4 +687,33 @@ public class PsiImplUtil { return element instanceof LeafElement && tokenSet.contains(((LeafElement)element).getElementType()); } + public static PsiType buildTypeFromTypeString(@NotNull final String typeName, @NotNull final PsiElement context, @NotNull final PsiFile psiFile) { + PsiType resultType; + final PsiManager psiManager = psiFile.getManager(); + + if (typeName.indexOf('<') != -1 || typeName.indexOf('[') != -1 || typeName.indexOf('.') == -1) { + try { + return JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory().createTypeFromText(typeName, context); + } catch(Exception ex) {} // invalid syntax will produce unresolved class type + } + + PsiClass aClass = JavaPsiFacade.getInstance(psiManager.getProject()).findClass(typeName, context.getResolveScope()); + + if (aClass == null) { + final LightClassReference ref = new LightClassReference( + psiManager, + PsiNameHelper.getShortClassName(typeName), + typeName, + PsiSubstitutor.EMPTY, + psiFile + ); + resultType = new PsiClassReferenceType(ref, null); + } else { + PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory(); + PsiSubstitutor substitutor = factory.createRawSubstitutor(aClass); + resultType = factory.createType(aClass, substitutor); + } + + return resultType; + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java index f1d847cb24c2..e0db7701574d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java @@ -18,6 +18,7 @@ package com.intellij.psi.impl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootModificationTracker; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; @@ -370,7 +371,12 @@ public class PsiSuperMethodImplUtil { if (result == null) { result = new HierarchicalMethodSignatureImpl((MethodSignatureBackedByPsiMethod)method.getSignature(PsiSubstitutor.EMPTY)); } - return CachedValueProvider.Result.create(result, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); + + Project project = aClass == null ? method.getProject() : aClass.getProject(); + // cache Cls method hierarchy until root changed + Object dependency = method instanceof PsiCompiledElement ? ProjectRootModificationTracker.getInstance(project) : + PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT; + return CachedValueProvider.Result.create(result, dependency); } }; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java index d2a66271353d..b356698428d8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java @@ -84,7 +84,8 @@ public class StubBuildingVisitor<T> extends ClassVisitor { @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - String fqn, shortName; + String fqn; + String shortName; if (myShortName != null && name.endsWith(myShortName)) { shortName = myShortName; fqn = name.length() == shortName.length() @@ -338,7 +339,8 @@ public class StubBuildingVisitor<T> extends ClassVisitor { if (fqn == null) return true; // impossible case, just ignore if (fqn.length() != signature.length()) return false; - int p = 0, dot; + int p = 0; + int dot; while ((dot = fqn.indexOf('.', p)) >= 0) { if (!signature.regionMatches(p, fqn, p, dot - p)) { return false; @@ -428,24 +430,10 @@ public class StubBuildingVisitor<T> extends ClassVisitor { List<String> args = new ArrayList<String>(); List<String> throwables = exceptions != null ? new ArrayList<String>() : null; - final PsiMethodStubImpl stub = new PsiMethodStubImpl(myResult, StringRef.fromString(canonicalMethodName), flags, null); + int modifiersMask = packMethodFlags(access, myResult.isInterface()); + final PsiMethodStubImpl stub = new PsiMethodStubImpl(myResult, StringRef.fromString(canonicalMethodName), flags, signature, args, throwables, desc, modifiersMask); - final PsiModifierListStub modList = new PsiModifierListStubImpl(stub, packMethodFlags(access, myResult.isInterface())); - - String returnType = null; - boolean parsedViaGenericSignature = false; - if (signature != null) { - try { - returnType = parseMethodViaGenericSignature(signature, stub, args, throwables); - parsedViaGenericSignature = true; - } - catch (ClsFormatException ignored) { } - } - if (returnType == null) { - returnType = parseMethodViaDescription(desc, stub, args); - } - - stub.setReturnType(TypeInfo.fromString(returnType)); + PsiModifierListStub modList = (PsiModifierListStub)stub.findChildStubByType(JavaStubElementTypes.MODIFIER_LIST); if (isEnum && isConstructor && signature == null && args.size() >= 2 && JAVA_LANG_STRING.equals(args.get(0)) && "int".equals(args.get(1))) { // exclude synthetic enum constructor parameters @@ -454,6 +442,7 @@ public class StubBuildingVisitor<T> extends ClassVisitor { final boolean isNonStaticInnerClassConstructor = isConstructor && !(myParent instanceof PsiFileStub) && (myModList.getModifiersMask() & Opcodes.ACC_STATIC) == 0; + boolean parsedViaGenericSignature = stub.isParsedViaGenericSignature(); final boolean shouldSkipFirstParamForNonStaticInnerClassConstructor = !parsedViaGenericSignature && isNonStaticInnerClassConstructor; final PsiParameterListStubImpl parameterList = new PsiParameterListStubImpl(stub); @@ -502,7 +491,8 @@ public class StubBuildingVisitor<T> extends ClassVisitor { } } - private static String parseMethodViaDescription(final String desc, final PsiMethodStubImpl stub, final List<String> args) { + @NotNull + public static String parseMethodViaDescription(@NotNull String desc, @NotNull PsiMethodStubImpl stub, @NotNull List<String> args) { final String returnType = getTypeText(Type.getReturnType(desc)); final Type[] argTypes = Type.getArgumentTypes(desc); for (Type argType : argTypes) { @@ -512,10 +502,11 @@ public class StubBuildingVisitor<T> extends ClassVisitor { return returnType; } - private static String parseMethodViaGenericSignature(final String signature, - final PsiMethodStubImpl stub, - final List<String> args, - final List<String> throwables) throws ClsFormatException { + @NotNull + public static String parseMethodViaGenericSignature(@NotNull String signature, + @NotNull PsiMethodStubImpl stub, + @NotNull List<String> args, + @Nullable List<String> throwables) throws ClsFormatException { StringCharacterIterator iterator = new StringCharacterIterator(signature); SignatureParsing.parseTypeParametersDeclaration(iterator, stub); @@ -651,12 +642,12 @@ public class StubBuildingVisitor<T> extends ClassVisitor { private int myUsedParamSize = 0; private int myUsedParamCount = 0; - private AnnotationParamCollectingVisitor(final PsiMethodStub owner, - final PsiModifierListStub modList, + private AnnotationParamCollectingVisitor(@NotNull PsiMethodStub owner, + @NotNull PsiModifierListStub modList, final int ignoreCount, final int paramIgnoreCount, final int paramCount, - final PsiParameterStubImpl[] paramStubs) { + @NotNull PsiParameterStubImpl[] paramStubs) { super(ASM_API); myOwner = owner; myModList = modList; @@ -758,7 +749,7 @@ public class StubBuildingVisitor<T> extends ClassVisitor { } if (value instanceof Double) { - final double d = ((Double)value).doubleValue(); + final double d = (Double)value; if (Double.isInfinite(d)) { return d > 0 ? DOUBLE_POSITIVE_INF : DOUBLE_NEGATIVE_INF; } @@ -769,7 +760,7 @@ public class StubBuildingVisitor<T> extends ClassVisitor { } if (value instanceof Float) { - final float v = ((Float)value).floatValue(); + final float v = (Float)value; if (Float.isInfinite(v)) { return v > 0 ? FLOAT_POSITIVE_INF : FLOAT_NEGATIVE_INF; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java index 1463355455c2..13487c5514d0 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -21,19 +21,23 @@ package com.intellij.psi.impl.java.stubs.impl; import com.intellij.psi.PsiMethod; import com.intellij.psi.impl.cache.TypeInfo; +import com.intellij.psi.impl.compiled.StubBuildingVisitor; import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; import com.intellij.psi.impl.java.stubs.PsiMethodStub; import com.intellij.psi.impl.java.stubs.PsiParameterListStub; import com.intellij.psi.impl.java.stubs.PsiParameterStub; import com.intellij.psi.stubs.StubBase; import com.intellij.psi.stubs.StubElement; +import com.intellij.util.BitUtil; +import com.intellij.util.cls.ClsFormatException; import com.intellij.util.io.StringRef; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; public class PsiMethodStubImpl extends StubBase<PsiMethod> implements PsiMethodStub { - private TypeInfo myReturnType; + private final TypeInfo myReturnType; private final byte myFlags; private final StringRef myName; private StringRef myDefaultValueText; @@ -43,15 +47,40 @@ public class PsiMethodStubImpl extends StubBase<PsiMethod> implements PsiMethodS private static final int ANNOTATION = 0x04; private static final int DEPRECATED = 0x08; private static final int DEPRECATED_ANNOTATION = 0x10; - - public PsiMethodStubImpl(StubElement parent, StringRef name, byte flags, StringRef defaultValueText) { + private static final int PARSED_VIA_GENERIC_SIGNATURE = 0x20; + + public PsiMethodStubImpl(StubElement parent, + StringRef name, + byte flags, + String signature, + @NotNull List<String> args, + @Nullable List<String> throwables, + String desc, + int modifiersMask) { super(parent, isAnnotationMethod(flags) ? JavaStubElementTypes.ANNOTATION_METHOD : JavaStubElementTypes.METHOD); - myFlags = flags; myName = name; - myDefaultValueText = defaultValueText; + myDefaultValueText = null; + + new PsiModifierListStubImpl(this, modifiersMask); + + String returnType = null; + boolean parsedViaGenericSignature = false; + if (signature != null) { + try { + returnType = StubBuildingVisitor.parseMethodViaGenericSignature(signature, this, args, throwables); + parsedViaGenericSignature = true; + } + catch (ClsFormatException ignored) { } + } + if (returnType == null) { + returnType = StubBuildingVisitor.parseMethodViaDescription(desc, this, args); + } + + myReturnType = TypeInfo.fromString(returnType); + myFlags = (byte)(flags | (parsedViaGenericSignature ? PARSED_VIA_GENERIC_SIGNATURE : 0)); } - public PsiMethodStubImpl(StubElement parent, StringRef name, TypeInfo returnType, byte flags, StringRef defaultValueText) { + public PsiMethodStubImpl(StubElement parent, StringRef name, @NotNull TypeInfo returnType, byte flags, StringRef defaultValueText) { super(parent, isAnnotationMethod(flags) ? JavaStubElementTypes.ANNOTATION_METHOD : JavaStubElementTypes.METHOD); myReturnType = returnType; myFlags = flags; @@ -59,10 +88,6 @@ public class PsiMethodStubImpl extends StubBase<PsiMethod> implements PsiMethodS myDefaultValueText = defaultValueText; } - public void setReturnType(TypeInfo returnType) { - myReturnType = returnType; - } - @Override public boolean isConstructor() { return (myFlags & CONSTRUCTOR) != 0; @@ -73,6 +98,9 @@ public class PsiMethodStubImpl extends StubBase<PsiMethod> implements PsiMethodS return (myFlags & VARARGS) != 0; } + public boolean isParsedViaGenericSignature() { + return BitUtil.isSet(myFlags, PARSED_VIA_GENERIC_SIGNATURE); + } @Override public boolean isAnnotationMethod() { return isAnnotationMethod(myFlags); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java index 58b1e2253d14..b2c934ef9783 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveCache.java @@ -86,12 +86,13 @@ public class JavaResolveCache { @Nullable public <T extends PsiExpression> PsiType getType(@NotNull T expr, @NotNull Function<T, PsiType> f) { - PsiType type = getCachedType(expr); + final boolean isOverloadCheck = MethodCandidateInfo.isOverloadCheck(); + PsiType type = !isOverloadCheck ? getCachedType(expr) : null; if (type == null) { final RecursionGuard.StackStamp dStackStamp = PsiDiamondType.ourDiamondGuard.markStack(); final RecursionGuard.StackStamp gStackStamp = PsiResolveHelper.ourGraphGuard.markStack(); type = f.fun(expr); - if (!dStackStamp.mayCacheNow() || !gStackStamp.mayCacheNow() || !MethodCandidateInfo.ourOverloadGuard.currentStack().isEmpty()) { + if (!dStackStamp.mayCacheNow() || !gStackStamp.mayCacheNow() || isOverloadCheck) { return type; } if (type == null) type = TypeConversionUtil.NULL_TYPE; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index 6098199c591c..7d6166a7f95a 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -349,13 +349,17 @@ public class InferenceSession { } public boolean initBounds(PsiTypeParameter... typeParameters) { + return initBounds(myContext, typeParameters); + } + + public boolean initBounds(PsiElement context, PsiTypeParameter... typeParameters) { boolean sameMethodCall = false; for (PsiTypeParameter parameter : typeParameters) { if (myInferenceVariables.containsKey(parameter)) { sameMethodCall = true; continue; } - InferenceVariable variable = new InferenceVariable(parameter); + InferenceVariable variable = new InferenceVariable(context, parameter); boolean added = false; final PsiClassType[] extendsListTypes = parameter.getExtendsListTypes(); for (PsiType classType : extendsListTypes) { @@ -415,7 +419,7 @@ public class InferenceSession { for (int i = 0; i < typeParameters.length; i++) { PsiTypeParameter typeParameter = typeParameters[i]; copy[i] = elementFactory.createTypeParameterFromText("rCopy" + typeParameter.getName(), null); - initBounds(copy[i]); + initBounds(myContext, copy[i]); subst = subst.put(typeParameter, elementFactory.createType(copy[i])); } final PsiType substitutedCapture = PsiUtil.captureToplevelWildcards(subst.substitute(returnType), myContext); @@ -446,7 +450,7 @@ public class InferenceSession { } private static boolean hasPrimitiveWrapperBound(InferenceVariable inferenceVariable) { - final InferenceBound[] boundTypes = {InferenceBound.UPPER, InferenceBound.LOWER}; + final InferenceBound[] boundTypes = {InferenceBound.UPPER, InferenceBound.LOWER, InferenceBound.EQ}; for (InferenceBound inferenceBound : boundTypes) { final List<PsiType> bounds = inferenceVariable.getBounds(inferenceBound); for (PsiType bound : bounds) { @@ -701,7 +705,7 @@ public class InferenceSession { final PsiTypeParameter copy = elementFactory.createTypeParameterFromText("z" + parameter.getName(), null); final PsiType lub = getLowerBound(var, substitutor); final PsiType glb = getUpperBound(var, substitutor); - final InferenceVariable zVariable = new InferenceVariable(copy); + final InferenceVariable zVariable = new InferenceVariable(var.getCallContext(), copy); zVariable.addBound(glb, InferenceBound.UPPER); if (lub != PsiType.NULL) { if (!TypeConversionUtil.isAssignable(glb, lub)) { @@ -1026,7 +1030,7 @@ public class InferenceSession { boolean varargs) { final InferenceSession session = new InferenceSession(PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY, m2.getManager(), context); for (PsiTypeParameter param : PsiUtil.typeParametersIterable(m2)) { - session.initBounds(param); + session.initBounds(context, param); } final PsiParameter[] parameters1 = m1.getParameterList().getParameters(); @@ -1250,14 +1254,17 @@ public class InferenceSession { return myIncorporationPhase.hasCaptureConstraints(Arrays.asList(inferenceVariable)); } - public void liftBounds(Collection<InferenceVariable> variables) { + public void liftBounds(PsiElement context, Collection<InferenceVariable> variables) { for (InferenceVariable variable : variables) { final PsiTypeParameter parameter = variable.getParameter(); final InferenceVariable inferenceVariable = getInferenceVariable(parameter); if (inferenceVariable != null) { - for (InferenceBound boundType : InferenceBound.values()) { - for (PsiType bound : variable.getBounds(boundType)) { - inferenceVariable.addBound(bound, boundType); + final PsiElement callContext = inferenceVariable.getCallContext(); + if (context.equals(callContext) || myContext.equals(callContext)) { + for (InferenceBound boundType : InferenceBound.values()) { + for (PsiType bound : variable.getBounds(boundType)) { + inferenceVariable.addBound(bound, boundType); + } } } } else { @@ -1270,4 +1277,8 @@ public class InferenceSession { final Boolean erased = call.getUserData(ERASED); return erased != null && erased.booleanValue(); } + + public PsiElement getContext() { + return myContext; + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java index a606e90e8a98..a19961f4c3a9 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java @@ -26,6 +26,8 @@ import java.util.*; * User: anna */ public class InferenceVariable extends LightTypeParameter { + private PsiElement myContext; + public PsiTypeParameter getParameter() { return getDelegate(); } @@ -35,8 +37,9 @@ public class InferenceVariable extends LightTypeParameter { private PsiType myInstantiation = PsiType.NULL; - InferenceVariable(PsiTypeParameter parameter) { + InferenceVariable(PsiElement context, PsiTypeParameter parameter) { super(parameter); + myContext = context; } public PsiType getInstantiation() { @@ -129,4 +132,8 @@ public class InferenceVariable extends LightTypeParameter { public String toString() { return getDelegate().toString(); } + + public PsiElement getCallContext() { + return myContext; + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index c33e2c31fa12..82b320ae99f3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -110,7 +110,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm if (typeParams != null) { final Set<PsiTypeParameter> oldBounds = ContainerUtil.newHashSet(session.getParamsToInfer()); - final boolean sameMethodCall = session.initBounds(typeParams); + final boolean sameMethodCall = session.initBounds(myExpression, typeParams); PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; final HashSet<InferenceVariable> variables = new HashSet<InferenceVariable>(); session.collectDependencies(returnType, variables); @@ -138,8 +138,8 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm } final Collection<PsiTypeParameter> params1 = session.getTypeParams(); - final InferenceSession callSession = new InferenceSession(params1.toArray(new PsiTypeParameter[params1.size()]), substitutor, myExpression.getManager(), myExpression); - callSession.initBounds(params); + final InferenceSession callSession = new InferenceSession(params, substitutor, myExpression.getManager(), myExpression); + callSession.initBounds(session.getContext(), params1.toArray(new PsiTypeParameter[params1.size()])); if (method != null) { final PsiExpression[] args = argumentList.getExpressions(); final PsiParameter[] parameters = method.getParameterList().getParameters(); @@ -163,7 +163,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm } } } - session.liftBounds(inferenceVariables); + session.liftBounds(myExpression, inferenceVariables); } else { return false; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java index 18d0c49e79d4..9516265a8cb5 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java @@ -91,7 +91,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm } final PsiParameter[] parameters = applicableMember instanceof PsiMethod ? ((PsiMethod)applicableMember).getParameterList().getParameters() : PsiParameter.EMPTY_ARRAY; if (targetParameters.length == parameters.length + 1) { - specialCase(session, constraints, substitutor, targetParameters); + specialCase(session, constraints, substitutor, targetParameters, true); for (int i = 1; i < targetParameters.length; i++) { constraints.add(new TypeCompatibilityConstraint(psiSubstitutor.substitute(parameters[i - 1].getType()), substitutor.substitute(targetParameters[i].getType()))); } @@ -198,7 +198,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm final PsiParameter[] parameters = method.getParameterList().getParameters(); if (targetParameters.length == parameters.length + 1 && !method.isVarArgs() && PsiPolyExpressionUtil.mentionsTypeParameters(referencedMethodReturnType, ContainerUtil.newHashSet(containingClass.getTypeParameters()))) { //todo specification bug? - specialCase(session, constraints, substitutor, targetParameters); + specialCase(session, constraints, substitutor, targetParameters, false); } constraints.add(new TypeCompatibilityConstraint(returnType, psiSubstitutor.substitute(referencedMethodReturnType))); } @@ -209,7 +209,8 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm private void specialCase(InferenceSession session, List<ConstraintFormula> constraints, PsiSubstitutor substitutor, - PsiParameter[] targetParameters) { + PsiParameter[] targetParameters, + boolean ignoreRaw) { final PsiElement qualifier = myExpression.getQualifier(); PsiType qualifierType = null; if (qualifier instanceof PsiTypeElement) { @@ -226,8 +227,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm final PsiElement res = resolveResult.getElement(); if (res instanceof PsiClass) { PsiClass containingClass = (PsiClass)res; - final boolean isRawSubst = !myExpression.isConstructor() && - PsiUtil.isRawSubstitutor(containingClass, resolveResult.getSubstitutor()); + final boolean isRawSubst = !ignoreRaw && !myExpression.isConstructor() && PsiUtil.isRawSubstitutor(containingClass, resolveResult.getSubstitutor()); qualifierType = JavaPsiFacade.getElementFactory(res.getProject()).createType(containingClass, isRawSubst ? PsiSubstitutor.EMPTY : resolveResult.getSubstitutor()); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSourceUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSourceUtil.java index e2af7b08df0d..d4d0f3f0c88d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSourceUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSourceUtil.java @@ -22,6 +22,7 @@ import com.intellij.lang.LighterASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.DummyHolder; import com.intellij.psi.impl.source.SourceJavaCodeReference; import com.intellij.psi.impl.source.SourceTreeToPsiMap; @@ -142,4 +143,41 @@ public class JavaSourceUtil { TreeUtil.clearCaches(TreeUtil.getFileElement(parenthExpr)); return parenthExpr; } + + public static void deleteSeparatingComma(@NotNull CompositeElement element, @NotNull ASTNode child) { + assert child.getElementType() != JavaTokenType.COMMA : child; + + ASTNode next = PsiImplUtil.skipWhitespaceAndComments(child.getTreeNext()); + if (next != null && next.getElementType() == JavaTokenType.COMMA) { + element.deleteChildInternal(next); + } + else { + ASTNode prev = PsiImplUtil.skipWhitespaceAndCommentsBack(child.getTreePrev()); + if (prev != null && prev.getElementType() == JavaTokenType.COMMA) { + element.deleteChildInternal(prev); + } + } + } + + public static void addSeparatingComma(@NotNull CompositeElement element, @NotNull ASTNode child, @NotNull TokenSet listTypes) { + assert child.getElementType() != JavaTokenType.COMMA : child; + + scanChildren(element, child, listTypes, true); + scanChildren(element, child, listTypes, false); + } + + private static void scanChildren(CompositeElement element, ASTNode node, TokenSet listTypes, boolean forward) { + ASTNode child = node; + while (true) { + child = (forward ? child.getTreeNext() : child.getTreePrev()); + if (child == null || child.getElementType() == JavaTokenType.COMMA) break; + if (listTypes.contains(child.getElementType())) { + CharTable charTable = SharedImplUtil.findCharTableByTree(element); + PsiManager manager = element.getPsi().getManager(); + TreeElement comma = Factory.createSingleLeafElement(JavaTokenType.COMMA, ",", 0, 1, charTable, manager); + element.addInternal(comma, comma, (forward ? node : child), Boolean.FALSE); + break; + } + } + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/AnnotationParamListElement.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/AnnotationParamListElement.java index 4953bd2d3804..e1ffc8b91766 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/AnnotationParamListElement.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/AnnotationParamListElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -19,8 +19,9 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.*; -import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.ChildRoleBase; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import com.intellij.util.CharTable; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -28,47 +29,29 @@ import org.jetbrains.annotations.NotNull; /** * @author ven */ -public class AnnotationParamListElement extends PsiCommaSeparatedListImpl implements PsiAnnotationParameterList { +public class AnnotationParamListElement extends CompositeElement { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.AnnotationParamListElement"); - private volatile PsiNameValuePair[] myCachedMembers = null; + private static final TokenSet NAME_VALUE_PAIR_BIT_SET = TokenSet.create(JavaElementType.NAME_VALUE_PAIR); public AnnotationParamListElement() { - super(ANNOTATION_PARAMETER_LIST, NAME_VALUE_PAIR_BIT_SET); - } - - @Override - public void clearCaches() { - super.clearCaches(); - myCachedMembers = null; - } - - @Override - @NotNull - public PsiNameValuePair[] getAttributes() { - PsiNameValuePair[] cachedMembers = myCachedMembers; - if (cachedMembers == null) { - myCachedMembers = cachedMembers = getChildrenAsPsiElements(NAME_VALUE_PAIR_BIT_SET, PsiNameValuePair.ARRAY_FACTORY); - } - - return cachedMembers; + super(JavaElementType.ANNOTATION_PARAMETER_LIST); } @Override public int getChildRole(ASTNode child) { IElementType i = child.getElementType(); - if (i == COMMA) { + if (i == JavaTokenType.COMMA) { return ChildRole.COMMA; } - else if (i == LPARENTH) { + else if (i == JavaTokenType.LPARENTH) { return ChildRole.LPARENTH; } - else if (i == RPARENTH) { + else if (i == JavaTokenType.RPARENTH) { return ChildRole.RPARENTH; } - else if (ANNOTATION_MEMBER_VALUE_BIT_SET.contains(child.getElementType()) - || (i == NAME_VALUE_PAIR && child.getFirstChildNode() != null - && child.getFirstChildNode().getElementType() == ANNOTATION_ARRAY_INITIALIZER)) - { + else if (ElementType.ANNOTATION_MEMBER_VALUE_BIT_SET.contains(i) || + (i == JavaElementType.NAME_VALUE_PAIR && child.getFirstChildNode() != null && + child.getFirstChildNode().getElementType() == JavaElementType.ANNOTATION_ARRAY_INITIALIZER)) { return ChildRole.ANNOTATION_VALUE; } else { @@ -83,65 +66,69 @@ public class AnnotationParamListElement extends PsiCommaSeparatedListImpl implem LOG.assertTrue(false); return null; case ChildRole.LPARENTH: - return findChildByType(LPARENTH); + return findChildByType(JavaTokenType.LPARENTH); case ChildRole.RPARENTH: - return findChildByType(RPARENTH); - } - } - - public String toString() { - return "PsiAnnotationParameterList"; - } - - @Override - public void accept(@NotNull PsiElementVisitor visitor) { - if (visitor instanceof JavaElementVisitor) { - ((JavaElementVisitor)visitor).visitAnnotationParameterList(this); - } - else { - visitor.visitElement(this); + return findChildByType(JavaTokenType.RPARENTH); } } @Override public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before) { - if (first.getElementType() == NAME_VALUE_PAIR && last.getElementType() == NAME_VALUE_PAIR) { - final CharTable treeCharTab = SharedImplUtil.findCharTableByTree(this); - ASTNode lparenth = findChildByRole(ChildRole.LPARENTH); + if (first.getElementType() == JavaElementType.NAME_VALUE_PAIR && last.getElementType() == JavaElementType.NAME_VALUE_PAIR) { + ASTNode lparenth = findChildByType(JavaTokenType.LPARENTH); if (lparenth == null) { - LeafElement created = Factory.createSingleLeafElement(LPARENTH, "(", 0, 1, treeCharTab, getManager()); + CharTable treeCharTab = SharedImplUtil.findCharTableByTree(this); + LeafElement created = Factory.createSingleLeafElement(JavaTokenType.LPARENTH, "(", 0, 1, treeCharTab, getManager()); super.addInternal(created, created, getFirstChildNode(), true); } - ASTNode rparenth = findChildByRole(ChildRole.RPARENTH); + + ASTNode rparenth = findChildByType(JavaTokenType.RPARENTH); if (rparenth == null) { - LeafElement created = Factory.createSingleLeafElement(RPARENTH, ")", 0, 1, treeCharTab, getManager()); + CharTable treeCharTab = SharedImplUtil.findCharTableByTree(this); + LeafElement created = Factory.createSingleLeafElement(JavaTokenType.RPARENTH, ")", 0, 1, treeCharTab, getManager()); super.addInternal(created, created, getLastChildNode(), false); } - final ASTNode[] nodes = getChildren(NAME_VALUE_PAIR_BIT_SET); + ASTNode[] nodes = getChildren(NAME_VALUE_PAIR_BIT_SET); if (nodes.length == 1) { - final ASTNode node = nodes[0]; + ASTNode node = nodes[0]; if (node instanceof PsiNameValuePair) { - final PsiNameValuePair pair = (PsiNameValuePair)node; + PsiNameValuePair pair = (PsiNameValuePair)node; if (pair.getName() == null) { - final String text = pair.getValue().getText(); - try { - final PsiAnnotation annotation = JavaPsiFacade.getInstance(getProject()).getElementFactory().createAnnotationFromText("@AAA(value = " + text + ")", null); - replaceChild(node, annotation.getParameterList().getAttributes()[0].getNode()); - } - catch (IncorrectOperationException e) { - LOG.error(e); + PsiAnnotationMemberValue value = pair.getValue(); + if (value != null) { + try { + PsiElementFactory factory = JavaPsiFacade.getInstance(getPsi().getProject()).getElementFactory(); + PsiAnnotation annotation = factory.createAnnotationFromText("@AAA(value = " + value.getText() + ")", null); + replaceChild(node, annotation.getParameterList().getAttributes()[0].getNode()); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } } } } if (anchor == null && before != null) { - anchor = findChildByRole(before.booleanValue() ? ChildRole.RPARENTH : ChildRole.LPARENTH); + anchor = findChildByType(before ? JavaTokenType.RPARENTH : JavaTokenType.LPARENTH); } + + TreeElement firstAdded = super.addInternal(first, last, anchor, before); + JavaSourceUtil.addSeparatingComma(this, first, NAME_VALUE_PAIR_BIT_SET); + return firstAdded; } return super.addInternal(first, last, anchor, before); } + + @Override + public void deleteChildInternal(@NotNull ASTNode child) { + if (child.getElementType() == JavaElementType.NAME_VALUE_PAIR) { + JavaSourceUtil.deleteSeparatingComma(this, child); + } + + super.deleteChildInternal(child); + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java index 712b32ca6d5b..14d72a92da1c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ClassElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -34,6 +34,15 @@ import org.jetbrains.annotations.Nullable; public class ClassElement extends CompositeElement implements Constants { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.ClassElement"); + private static final TokenSet MODIFIERS_TO_REMOVE_IN_INTERFACE_BIT_SET = TokenSet.create( + PUBLIC_KEYWORD, ABSTRACT_KEYWORD, STATIC_KEYWORD, FINAL_KEYWORD, NATIVE_KEYWORD); + private static final TokenSet MODIFIERS_TO_REMOVE_IN_INTERFACE_BIT_SET_18_METHOD = TokenSet.create( + PUBLIC_KEYWORD, ABSTRACT_KEYWORD, FINAL_KEYWORD, NATIVE_KEYWORD); + private static final TokenSet MODIFIERS_TO_REMOVE_IN_ENUM_BIT_SET = TokenSet.create( + PUBLIC_KEYWORD, FINAL_KEYWORD); + private static final TokenSet ENUM_CONSTANT_LIST_ELEMENTS_BIT_SET = TokenSet.create( + ENUM_CONSTANT, COMMA, SEMICOLON); + public ClassElement(IElementType type) { super(type); } @@ -181,19 +190,8 @@ public class ClassElement extends CompositeElement implements Constants { @Override public void deleteChildInternal(@NotNull ASTNode child) { - if (isEnum()) { - if (child.getElementType() == ENUM_CONSTANT) { - ASTNode next = PsiImplUtil.skipWhitespaceAndComments(child.getTreeNext()); - if (next != null && next.getElementType() == COMMA) { - deleteChildInternal(next); - } - else { - ASTNode prev = PsiImplUtil.skipWhitespaceAndCommentsBack(child.getTreePrev()); - if (prev != null && prev.getElementType() == COMMA) { - deleteChildInternal(prev); - } - } - } + if (isEnum() && child.getElementType() == ENUM_CONSTANT) { + JavaSourceUtil.deleteSeparatingComma(this, child); } if (child.getElementType() == FIELD) { @@ -233,27 +231,6 @@ public class ClassElement extends CompositeElement implements Constants { return findChildByRole(ChildRole.AT) != null; } - private static final TokenSet MODIFIERS_TO_REMOVE_IN_INTERFACE_BIT_SET = TokenSet.create( - PUBLIC_KEYWORD, ABSTRACT_KEYWORD, - STATIC_KEYWORD, FINAL_KEYWORD, - NATIVE_KEYWORD - ); - - private static final TokenSet MODIFIERS_TO_REMOVE_IN_INTERFACE_BIT_SET_18_METHOD = TokenSet.create( - PUBLIC_KEYWORD, ABSTRACT_KEYWORD, - FINAL_KEYWORD, - NATIVE_KEYWORD - ); - - private static final TokenSet MODIFIERS_TO_REMOVE_IN_ENUM_BIT_SET = TokenSet.create( - PUBLIC_KEYWORD, FINAL_KEYWORD - ); - - private static final TokenSet ENUM_CONSTANT_LIST_ELEMENTS_BIT_SET = TokenSet.create( - ENUM_CONSTANT, COMMA, SEMICOLON - ); - - @Override public ASTNode findChildByRole(int role) { assert ChildRole.isUnique(role); @@ -266,10 +243,7 @@ public class ClassElement extends CompositeElement implements Constants { return PsiImplUtil.findDocComment(this); case ChildRole.ENUM_CONSTANT_LIST_DELIMITER: - if (!isEnum()) { - return null; - } - return findEnumConstantListDelimiter(); + return isEnum() ? findEnumConstantListDelimiter() : null; case ChildRole.MODIFIER_LIST: return findChildByType(MODIFIER_LIST); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ParameterListElement.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ParameterListElement.java index a5e32e9ce95b..20d504d8dbae 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ParameterListElement.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ParameterListElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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,18 +18,21 @@ package com.intellij.psi.impl.source.tree.java; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.Constants; -import com.intellij.psi.impl.source.tree.*; +import com.intellij.psi.impl.source.tree.ChildRole; +import com.intellij.psi.impl.source.tree.CompositeElement; +import com.intellij.psi.impl.source.tree.JavaSourceUtil; +import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.tree.ChildRoleBase; import com.intellij.psi.tree.IElementType; -import com.intellij.util.CharTable; +import com.intellij.psi.tree.TokenSet; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class ParameterListElement extends CompositeElement implements Constants { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.ParameterListElement"); + private static final TokenSet PARAMETER_SET = TokenSet.create(PARAMETER); public ParameterListElement() { super(PARAMETER_LIST); @@ -49,23 +52,7 @@ public class ParameterListElement extends CompositeElement implements Constants } TreeElement firstAdded = super.addInternal(first, last, anchor, before); if (first == last && first.getElementType() == PARAMETER) { - final CharTable treeCharTab = SharedImplUtil.findCharTableByTree(this); - for (ASTNode child = ((ASTNode)first).getTreeNext(); child != null; child = child.getTreeNext()) { - if (child.getElementType() == COMMA) break; - if (child.getElementType() == PARAMETER) { - TreeElement comma = Factory.createSingleLeafElement(COMMA, ",", 0, 1, treeCharTab, getManager()); - super.addInternal(comma, comma, first, Boolean.FALSE); - break; - } - } - for (ASTNode child = ((ASTNode)first).getTreePrev(); child != null; child = child.getTreePrev()) { - if (child.getElementType() == COMMA) break; - if (child.getElementType() == PARAMETER) { - TreeElement comma = Factory.createSingleLeafElement(COMMA, ",", 0, 1, treeCharTab, getManager()); - super.addInternal(comma, comma, child, Boolean.FALSE); - break; - } - } + JavaSourceUtil.addSeparatingComma(this, first, PARAMETER_SET); } //todo[max] hack? @@ -83,16 +70,7 @@ public class ParameterListElement extends CompositeElement implements Constants final TreeElement oldLastNodeInsideParens = getLastNodeInsideParens(); final TreeElement oldFirstNodeInsideParens = getFirstNodeInsideParens(); if (child.getElementType() == PARAMETER) { - ASTNode next = PsiImplUtil.skipWhitespaceAndComments(child.getTreeNext()); - if (next != null && next.getElementType() == COMMA) { - deleteChildInternal(next); - } - else { - ASTNode prev = PsiImplUtil.skipWhitespaceAndCommentsBack(child.getTreePrev()); - if (prev != null && prev.getElementType() == COMMA) { - deleteChildInternal(prev); - } - } + JavaSourceUtil.deleteSeparatingComma(this, child); } super.deleteChildInternal(child); @@ -135,20 +113,12 @@ public class ParameterListElement extends CompositeElement implements Constants return null; case ChildRole.LPARENTH: - if (getFirstChildNode().getElementType() == LPARENTH) { - return getFirstChildNode(); - } - else { - return null; - } + TreeElement firstNode = getFirstChildNode(); + return firstNode.getElementType() == LPARENTH ? firstNode : null; case ChildRole.RPARENTH: - if (getLastChildNode().getElementType() == RPARENTH) { - return getLastChildNode(); - } - else { - return null; - } + TreeElement lastNode = getLastChildNode(); + return lastNode.getElementType() == RPARENTH ? lastNode : null; } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiAnnotationParamListImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiAnnotationParamListImpl.java index 5a3ccb23e420..0923d7cdd675 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiAnnotationParamListImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiAnnotationParamListImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -16,20 +16,20 @@ package com.intellij.psi.impl.source.tree.java; import com.intellij.lang.ASTNode; +import com.intellij.psi.JavaElementVisitor; import com.intellij.psi.PsiAnnotationParameterList; +import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiNameValuePair; import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; import com.intellij.psi.impl.java.stubs.PsiAnnotationParameterListStub; import com.intellij.psi.impl.source.JavaStubPsiElement; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; /** * @author Dmitry Avdeev - * Date: 7/27/12 + * @since 27.07.2012 */ -public class PsiAnnotationParamListImpl extends JavaStubPsiElement<PsiAnnotationParameterListStub> implements - PsiAnnotationParameterList { +public class PsiAnnotationParamListImpl extends JavaStubPsiElement<PsiAnnotationParameterListStub> implements PsiAnnotationParameterList { public PsiAnnotationParamListImpl(@NotNull PsiAnnotationParameterListStub stub) { super(stub, JavaStubElementTypes.ANNOTATION_PARAMETER_LIST); } @@ -44,8 +44,18 @@ public class PsiAnnotationParamListImpl extends JavaStubPsiElement<PsiAnnotation return getStubOrPsiChildren(JavaStubElementTypes.NAME_VALUE_PAIR, PsiNameValuePair.ARRAY_FACTORY); } - @NonNls - public String toString(){ - return "PsiAnnotationParameterList:" + getText(); + @Override + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof JavaElementVisitor) { + ((JavaElementVisitor)visitor).visitAnnotationParameterList(this); + } + else { + visitor.visitElement(this); + } + } + + @Override + public String toString() { + return "PsiAnnotationParameterList"; } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiArrayInitializerMemberValueImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiArrayInitializerMemberValueImpl.java index dd64ed7e41fb..b03766f54d55 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiArrayInitializerMemberValueImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiArrayInitializerMemberValueImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -17,68 +17,84 @@ package com.intellij.psi.impl.source.tree.java; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.psi.JavaElementVisitor; -import com.intellij.psi.PsiAnnotationMemberValue; -import com.intellij.psi.PsiArrayInitializerMemberValue; -import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.impl.source.tree.ChildRole; -import com.intellij.psi.tree.IElementType; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.*; import com.intellij.psi.tree.ChildRoleBase; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; /** * @author ven */ -public class PsiArrayInitializerMemberValueImpl extends PsiCommaSeparatedListImpl implements PsiArrayInitializerMemberValue { - private static final Logger LOG = Logger.getInstance("com.intellij.psi.impl.source.tree.java.PsiArrayInitializerMemberValueImpl"); +public class PsiArrayInitializerMemberValueImpl extends CompositePsiElement implements PsiArrayInitializerMemberValue { + private static final Logger LOG = Logger.getInstance(PsiArrayInitializerMemberValueImpl.class); + private static final TokenSet MEMBER_SET = ElementType.ANNOTATION_MEMBER_VALUE_BIT_SET; + public PsiArrayInitializerMemberValueImpl() { - super(ANNOTATION_ARRAY_INITIALIZER, ANNOTATION_MEMBER_VALUE_BIT_SET); + super(JavaElementType.ANNOTATION_ARRAY_INITIALIZER); } @Override @NotNull public PsiAnnotationMemberValue[] getInitializers() { - return getChildrenAsPsiElements(ANNOTATION_MEMBER_VALUE_BIT_SET, PsiAnnotationMemberValue.ARRAY_FACTORY); + return getChildrenAsPsiElements(MEMBER_SET, PsiAnnotationMemberValue.ARRAY_FACTORY); } @Override public ASTNode findChildByRole(int role) { LOG.assertTrue(ChildRole.isUnique(role)); - switch(role){ + + switch (role) { default: return null; case ChildRole.LBRACE: - return findChildByType(LBRACE); + return findChildByType(JavaTokenType.LBRACE); case ChildRole.RBRACE: - return findChildByType(RBRACE); + return findChildByType(JavaTokenType.RBRACE); } } @Override public int getChildRole(ASTNode child) { LOG.assertTrue(child.getTreeParent() == this); + IElementType i = child.getElementType(); - if (i == COMMA) { + if (i == JavaTokenType.COMMA) { return ChildRole.COMMA; } - else if (i == LBRACE) { + else if (i == JavaTokenType.LBRACE) { return ChildRole.LBRACE; } - else if (i == RBRACE) { + else if (i == JavaTokenType.RBRACE) { return ChildRole.RBRACE; } - else { - if (ANNOTATION_MEMBER_VALUE_BIT_SET.contains(child.getElementType())) { - return ChildRole.ANNOTATION_VALUE; - } - return ChildRoleBase.NONE; + else if (MEMBER_SET.contains(child.getElementType())) { + return ChildRole.ANNOTATION_VALUE; } + return ChildRoleBase.NONE; } - public String toString(){ - return "PsiArrayInitializerMemberValue:" + getText(); + @Override + public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before) { + if (MEMBER_SET.contains(first.getElementType()) && MEMBER_SET.contains(last.getElementType())) { + TreeElement firstAdded = super.addInternal(first, last, anchor, before); + JavaSourceUtil.addSeparatingComma(this, first, MEMBER_SET); + return firstAdded; + } + + return super.addInternal(first, last, anchor, before); + } + + @Override + public void deleteChildInternal(@NotNull ASTNode child) { + if (MEMBER_SET.contains(child.getElementType())) { + JavaSourceUtil.deleteSeparatingComma(this, child); + } + + super.deleteChildInternal(child); } @Override @@ -90,4 +106,9 @@ public class PsiArrayInitializerMemberValueImpl extends PsiCommaSeparatedListImp visitor.visitElement(this); } } + + @Override + public String toString() { + return "PsiArrayInitializerMemberValue:" + getText(); + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiCommaSeparatedListImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiCommaSeparatedListImpl.java deleted file mode 100644 index 475542fdc868..000000000000 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiCommaSeparatedListImpl.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.psi.impl.source.tree.java; - -import com.intellij.lang.ASTNode; -import com.intellij.psi.impl.PsiImplUtil; -import com.intellij.psi.impl.source.Constants; -import com.intellij.psi.impl.source.tree.*; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.tree.TokenSet; -import com.intellij.util.CharTable; -import org.jetbrains.annotations.NotNull; - -/** - * Adds or removes comma - * - * @author ven - */ -public abstract class PsiCommaSeparatedListImpl extends CompositePsiElement implements Constants { - private final TokenSet myTypesOfElements; - - protected PsiCommaSeparatedListImpl(IElementType type, final TokenSet typeOfElements) { - super(type); - myTypesOfElements = typeOfElements; - } - - @Override - public TreeElement addInternal(TreeElement first, ASTNode last, ASTNode anchor, Boolean before) { - if (myTypesOfElements.contains(first.getElementType()) && myTypesOfElements.contains(last.getElementType())) { - final CharTable treeCharTab = SharedImplUtil.findCharTableByTree(this); - final TreeElement firstAdded = super.addInternal(first, last, anchor, before); - for (ASTNode child = ((ASTNode)first).getTreeNext(); child != null; child = child.getTreeNext()) { - if (child.getElementType() == COMMA) break; - if (myTypesOfElements.contains(child.getElementType())) { - TreeElement comma = Factory.createSingleLeafElement(COMMA, ",", 0, 1, treeCharTab, getManager()); - super.addInternal(comma, comma, first, Boolean.FALSE); - break; - } - } - - for (ASTNode child = ((ASTNode)first).getTreePrev(); child != null; child = child.getTreePrev()) { - if (child.getElementType() == COMMA) break; - if (myTypesOfElements.contains(child.getElementType())) { - TreeElement comma = Factory.createSingleLeafElement(COMMA, ",", 0, 1, treeCharTab, getManager()); - super.addInternal(comma, comma, child, Boolean.FALSE); - break; - } - } - return firstAdded; - } - - return super.addInternal(first, last, anchor, before); - } - - @Override - public void deleteChildInternal(@NotNull ASTNode child) { - if (myTypesOfElements.contains(child.getElementType())) { - ASTNode next = PsiImplUtil.skipWhitespaceAndComments(child.getTreeNext()); - if (next != null && next.getElementType() == COMMA) { - deleteChildInternal(next); - } - else { - ASTNode prev = PsiImplUtil.skipWhitespaceAndCommentsBack(child.getTreePrev()); - if (prev != null && prev.getElementType() == COMMA) { - deleteChildInternal(prev); - } - } - } - super.deleteChildInternal(child); - } -} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiExpressionListImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiExpressionListImpl.java index ae45273b57f1..98df0baa4134 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiExpressionListImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiExpressionListImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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,7 +18,6 @@ package com.intellij.psi.impl.source.tree.java; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; -import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.tree.*; import com.intellij.psi.tree.ChildRoleBase; import com.intellij.psi.tree.IElementType; @@ -123,7 +122,8 @@ public class PsiExpressionListImpl extends CompositePsiElement implements PsiExp } TreeElement firstAdded = super.addInternal(first, last, anchor, before); if (ElementType.EXPRESSION_BIT_SET.contains(first.getElementType())) { - ASTNode element = first; + JavaSourceUtil.addSeparatingComma(this, first, ElementType.EXPRESSION_BIT_SET); + /*ASTNode element = first; for (ASTNode child = element.getTreeNext(); child != null; child = child.getTreeNext()) { if (child.getElementType() == JavaTokenType.COMMA) break; if (ElementType.EXPRESSION_BIT_SET.contains(child.getElementType())) { @@ -140,7 +140,7 @@ public class PsiExpressionListImpl extends CompositePsiElement implements PsiExp super.addInternal(comma, comma, child, Boolean.FALSE); break; } - } + }*/ } return firstAdded; } @@ -148,17 +148,9 @@ public class PsiExpressionListImpl extends CompositePsiElement implements PsiExp @Override public void deleteChildInternal(@NotNull ASTNode child) { if (ElementType.EXPRESSION_BIT_SET.contains(child.getElementType())) { - ASTNode next = PsiImplUtil.skipWhitespaceAndComments(child.getTreeNext()); - if (next != null && next.getElementType() == JavaTokenType.COMMA) { - deleteChildInternal(next); - } - else { - ASTNode prev = PsiImplUtil.skipWhitespaceAndCommentsBack(child.getTreePrev()); - if (prev != null && prev.getElementType() == JavaTokenType.COMMA) { - deleteChildInternal(prev); - } - } + JavaSourceUtil.deleteSeparatingComma(this, child); } + super.deleteChildInternal(child); } @@ -172,6 +164,7 @@ public class PsiExpressionListImpl extends CompositePsiElement implements PsiExp } } + @Override public String toString() { return "PsiExpressionList"; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java index 95171ba30bc9..32ed1aac5c91 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java @@ -25,6 +25,7 @@ import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.impl.source.resolve.ResolveCache; import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; +import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.impl.source.tree.FileElement; import com.intellij.psi.impl.source.tree.JavaElementType; @@ -39,13 +40,12 @@ import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase implements PsiMethodReferenceExpression { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiMethodReferenceExpressionImpl"); @@ -153,7 +153,8 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase if (arrayClass == containingClass) { final PsiType componentType = qualifierResolveResult.getSubstitutor().substitute(arrayClass.getTypeParameters()[0]); LOG.assertTrue(componentType != null, qualifierResolveResult.getSubstitutor()); - methods = new PsiMethod[] {factory.createMethodFromText("public " + componentType.createArrayType().getCanonicalText() + " __array__(int i) {return null;}", this)}; + //15.13.1 A method reference expression of the form ArrayType :: new is always exact. + return factory.createMethodFromText("public " + componentType.createArrayType().getCanonicalText() + " __array__(int i) {return null;}", this); } else { methods = containingClass.getConstructors(); } @@ -172,25 +173,38 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase if (psiMethod.getTypeParameters().length > 0) { final PsiReferenceParameterList parameterList = getParameterList(); return parameterList != null && parameterList.getTypeParameterElements().length > 0 ? psiMethod : null; + } else { + final PsiSubstitutor classSubstitutor = TypeConversionUtil.getClassSubstitutor(psiMethod.getContainingClass(), containingClass, PsiSubstitutor.EMPTY); + final Set<PsiType> signature = new HashSet<PsiType>(Arrays.asList(psiMethod.getSignature(PsiSubstitutor.EMPTY).getParameterTypes())); + signature.add(psiMethod.getReturnType()); + boolean free = true; + for (PsiType type : signature) { + if (classSubstitutor != null) { + type = classSubstitutor.substitute(type); + } + if (type != null && PsiPolyExpressionUtil.mentionsTypeParameters(type, ContainerUtil.newHashSet(containingClass.getTypeParameters()))) { + free = false; + break; + } + } + if (free) return psiMethod; } } - if (containingClass.isPhysical() && containingClass.hasTypeParameters()) { + if (containingClass.hasTypeParameters()) { final PsiElement qualifier = getQualifier(); + PsiJavaCodeReferenceElement referenceElement = null; if (qualifier instanceof PsiTypeElement) { - final PsiJavaCodeReferenceElement referenceElement = ((PsiTypeElement)qualifier).getInnermostComponentReferenceElement(); - if (referenceElement != null) { - final PsiReferenceParameterList parameterList = referenceElement.getParameterList(); - if (parameterList == null || parameterList.getTypeParameterElements().length == 0) { - return null; - } - } + referenceElement = ((PsiTypeElement)qualifier).getInnermostComponentReferenceElement(); } else if (qualifier instanceof PsiReferenceExpression) { final PsiReferenceExpression expression = (PsiReferenceExpression)qualifier; if (qualifierResolveResult.isReferenceTypeQualified()) { - final PsiReferenceParameterList parameterList = expression.getParameterList(); - if (parameterList == null || parameterList.getTypeParameterElements().length == 0) { - return null; - } + referenceElement = expression; + } + } + if (referenceElement != null) { + final PsiReferenceParameterList parameterList = referenceElement.getParameterList(); + if (parameterList == null || parameterList.getTypeParameterElements().length == 0) { + return null; } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceParameterListImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceParameterListImpl.java index e85e81cb4bd8..743bd36abf5f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceParameterListImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceParameterListImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -22,6 +22,7 @@ import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.tree.*; import com.intellij.psi.tree.ChildRoleBase; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import com.intellij.util.CharTable; import org.jetbrains.annotations.NotNull; @@ -30,6 +31,7 @@ import org.jetbrains.annotations.NotNull; */ public class PsiReferenceParameterListImpl extends CompositePsiElement implements PsiReferenceParameterList { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiReferenceParameterListImpl"); + private static final TokenSet TYPE_SET = TokenSet.create(JavaElementType.TYPE); public PsiReferenceParameterListImpl() { super(JavaElementType.REFERENCE_PARAMETER_LIST); @@ -124,23 +126,8 @@ public class PsiReferenceParameterListImpl extends CompositePsiElement implement final TreeElement firstAdded = super.addInternal(first, last, anchor, before); - if (first == last && first.getElementType() == JavaElementType.TYPE){ - for(ASTNode child = first.getTreeNext(); child != null; child = child.getTreeNext()){ - if (child.getElementType() == JavaTokenType.COMMA) break; - if (child.getElementType() == JavaElementType.TYPE){ - TreeElement comma = Factory.createSingleLeafElement(JavaTokenType.COMMA, ",", 0, 1, treeCharTab, getManager()); - super.addInternal(comma, comma, first, Boolean.FALSE); - break; - } - } - for(ASTNode child = first.getTreePrev(); child != null; child = child.getTreePrev()){ - if (child.getElementType() == JavaTokenType.COMMA) break; - if (child.getElementType() == JavaElementType.TYPE){ - TreeElement comma = Factory.createSingleLeafElement(JavaTokenType.COMMA, ",", 0, 1, treeCharTab, getManager()); - super.addInternal(comma, comma, child, Boolean.FALSE); - break; - } - } + if (first == last && first.getElementType() == JavaElementType.TYPE) { + JavaSourceUtil.addSeparatingComma(this, first, TYPE_SET); } return firstAdded; @@ -148,17 +135,8 @@ public class PsiReferenceParameterListImpl extends CompositePsiElement implement @Override public void deleteChildInternal(@NotNull ASTNode child) { - if (child.getElementType() == JavaElementType.TYPE){ - ASTNode next = PsiImplUtil.skipWhitespaceAndComments(child.getTreeNext()); - if (next != null && next.getElementType() == JavaTokenType.COMMA){ - deleteChildInternal(next); - } - else{ - ASTNode prev = PsiImplUtil.skipWhitespaceAndCommentsBack(child.getTreePrev()); - if (prev != null && prev.getElementType() == JavaTokenType.COMMA){ - deleteChildInternal(prev); - } - } + if (child.getElementType() == JavaElementType.TYPE) { + JavaSourceUtil.deleteSeparatingComma(this, child); } super.deleteChildInternal(child); @@ -186,6 +164,7 @@ public class PsiReferenceParameterListImpl extends CompositePsiElement implement } } + @Override public String toString() { return "PsiReferenceParameterList"; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/TypeParameterListElement.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/TypeParameterListElement.java index 43d9d80c5742..2a3bdbaa2f4e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/TypeParameterListElement.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/TypeParameterListElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -22,6 +22,7 @@ import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.tree.*; import com.intellij.psi.tree.ChildRoleBase; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import com.intellij.util.CharTable; import org.jetbrains.annotations.NotNull; @@ -30,6 +31,7 @@ import org.jetbrains.annotations.NotNull; */ public class TypeParameterListElement extends CompositeElement { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.TypeParameterListElement"); + private static final TokenSet TYPE_PARAMETER_SET = TokenSet.create(JavaElementType.TYPE_PARAMETER); public TypeParameterListElement() { super(JavaElementType.TYPE_PARAMETER_LIST); @@ -82,25 +84,9 @@ public class TypeParameterListElement extends CompositeElement { } } - final TreeElement firstAdded = super.addInternal(first, last, anchor, before); - + TreeElement firstAdded = super.addInternal(first, last, anchor, before); if (first == last && first.getElementType() == JavaElementType.TYPE_PARAMETER) { - for(ASTNode child = first.getTreeNext(); child != null; child = child.getTreeNext()){ - if (child.getElementType() == JavaTokenType.COMMA) break; - if (child.getElementType() == JavaElementType.TYPE_PARAMETER){ - final TreeElement comma = Factory.createSingleLeafElement(JavaTokenType.COMMA, ",", 0, 1, treeCharTab, getManager()); - super.addInternal(comma, comma, first, Boolean.FALSE); - break; - } - } - for(ASTNode child = first.getTreePrev(); child != null; child = child.getTreePrev()){ - if (child.getElementType() == JavaTokenType.COMMA) break; - if (child.getElementType() == JavaElementType.TYPE_PARAMETER){ - final TreeElement comma = Factory.createSingleLeafElement(JavaTokenType.COMMA, ",", 0, 1, treeCharTab, getManager()); - super.addInternal(comma, comma, child, Boolean.FALSE); - break; - } - } + JavaSourceUtil.addSeparatingComma(this, first, TYPE_PARAMETER_SET); } return firstAdded; } @@ -108,18 +94,11 @@ public class TypeParameterListElement extends CompositeElement { @Override public void deleteChildInternal(@NotNull final ASTNode child) { if (child.getElementType() == JavaElementType.TYPE_PARAMETER){ - final ASTNode next = PsiImplUtil.skipWhitespaceAndComments(child.getTreeNext()); - if (next != null && next.getElementType() == JavaTokenType.COMMA){ - deleteChildInternal(next); - } - else{ - final ASTNode prev = PsiImplUtil.skipWhitespaceAndCommentsBack(child.getTreePrev()); - if (prev != null && prev.getElementType() == JavaTokenType.COMMA){ - deleteChildInternal(prev); - } - } + JavaSourceUtil.deleteSeparatingComma(this, child); } + super.deleteChildInternal(child); + if (child.getElementType() == JavaElementType.TYPE_PARAMETER) { final ASTNode lt = findChildByRole(ChildRole.LT_IN_TYPE_LIST); final ASTNode next = PsiImplUtil.skipWhitespaceAndComments(lt.getTreeNext()); diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index 59083c625f82..3d9ea08125a8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -316,7 +316,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ // prefer derived class signatures.put(signature, info); - } else { + } + else { final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(myArgumentsList, PsiMethodCallExpression.class); if (methodCallExpression != null) { final PsiReferenceExpression expression = methodCallExpression.getMethodExpression(); @@ -324,14 +325,16 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ PsiClass currentClass; if (qualifierExpression != null) { currentClass = PsiUtil.resolveClassInClassTypeOnly(qualifierExpression.getType()); - } else { + } + else { currentClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class); } - if (currentClass != null && InheritanceUtil.isInheritorOrSelf(currentClass, class1, true) && InheritanceUtil.isInheritorOrSelf(currentClass, existingClass, true)) { - final PsiSubstitutor eSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(existingClass, currentClass, PsiSubstitutor.EMPTY); - final PsiSubstitutor cSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(class1, currentClass, PsiSubstitutor.EMPTY); - if (MethodSignatureUtil.areSignaturesEqual(existingMethod.getSignature(eSubstitutor), method.getSignature(cSubstitutor))) { + if (currentClass != null) { + final PsiSubstitutor eSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(existingClass, currentClass, PsiSubstitutor.EMPTY, null); + final PsiSubstitutor cSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(class1, currentClass, PsiSubstitutor.EMPTY, null); + if (eSubstitutor != null && cSubstitutor != null && + MethodSignatureUtil.areSignaturesEqual(existingMethod.getSignature(eSubstitutor), method.getSignature(cSubstitutor))) { final PsiType returnType = eSubstitutor.substitute(existingMethod.getReturnType()); final PsiType returnType1 = cSubstitutor.substitute(method.getReturnType()); if (returnType != null && returnType1 != null && !returnType1.equals(returnType)) { diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java index 2b36a9c49b47..c12972d354c7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java @@ -83,7 +83,7 @@ public class MethodCandidatesProcessor extends MethodsProcessor{ public PsiType[] getArgumentTypes() { if (myExpressionTypes == null && argumentList != null) { final PsiType[] expressionTypes = getExpressionTypes(argumentList); - if (!MethodCandidateInfo.ourOverloadGuard.currentStack().isEmpty()) { + if (MethodCandidateInfo.isOverloadCheck()) { return expressionTypes; } myExpressionTypes = expressionTypes; diff --git a/java/java-structure-view/src/com/intellij/ide/structureView/impl/java/PsiMethodTreeElement.java b/java/java-structure-view/src/com/intellij/ide/structureView/impl/java/PsiMethodTreeElement.java index c1afbee6ada4..669080107623 100644 --- a/java/java-structure-view/src/com/intellij/ide/structureView/impl/java/PsiMethodTreeElement.java +++ b/java/java-structure-view/src/com/intellij/ide/structureView/impl/java/PsiMethodTreeElement.java @@ -51,12 +51,12 @@ public class PsiMethodTreeElement extends JavaClassTreeElementBase<PsiMethod> im final PsiMethod element = getElement(); if (element == null || element instanceof SyntheticElement) return result; - final TextRange range = element.getTextRange(); - if (range == null) return result; - final PsiFile psiFile = element.getContainingFile(); if (psiFile == null || psiFile instanceof PsiCompiledElement) return result; + final TextRange range = element.getTextRange(); + if (range == null) return result; + final String fileText = psiFile.getText(); if (fileText == null) return result; diff --git a/java/java-tests/testData/codeInsight/clsHighlighting/IDEA127714.java b/java/java-tests/testData/codeInsight/clsHighlighting/IDEA127714.java new file mode 100644 index 000000000000..08713f898f15 --- /dev/null +++ b/java/java-tests/testData/codeInsight/clsHighlighting/IDEA127714.java @@ -0,0 +1,9 @@ +import a.A; + +class IDEA127714 { + { + A<E, String> strings = new A<>(E.class); + } +} + +enum E {}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA127714.jar b/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA127714.jar Binary files differnew file mode 100644 index 000000000000..915d3a074810 --- /dev/null +++ b/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA127714.jar diff --git a/java/java-tests/testData/codeInsight/completeStatement/AlreadyCompleteCatch.java b/java/java-tests/testData/codeInsight/completeStatement/AlreadyCompleteCatch.java new file mode 100644 index 000000000000..d8ea6191cef8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completeStatement/AlreadyCompleteCatch.java @@ -0,0 +1,12 @@ + +class Foo { + { + try + { + + } catch (Ex<caret>ception e) + { + + } + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completeStatement/AlreadyCompleteCatch_after.java b/java/java-tests/testData/codeInsight/completeStatement/AlreadyCompleteCatch_after.java new file mode 100644 index 000000000000..f4874b45962e --- /dev/null +++ b/java/java-tests/testData/codeInsight/completeStatement/AlreadyCompleteCatch_after.java @@ -0,0 +1,12 @@ + +class Foo { + { + try + { + + } catch (Exception e) + { + <caret> + } + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/MulticaretCompletionFromNonPrimaryCaret.java b/java/java-tests/testData/codeInsight/completion/normal/MulticaretCompletionFromNonPrimaryCaret.java new file mode 100644 index 000000000000..077ff80bd5c7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/MulticaretCompletionFromNonPrimaryCaret.java @@ -0,0 +1,4 @@ +class Foo {{ + System.<caret> + System.<caret> +}} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/DontSuggestWildcardGenerics-out.java b/java/java-tests/testData/codeInsight/completion/smartType/DontSuggestWildcardGenerics-out.java new file mode 100644 index 000000000000..41f3d57525a2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/DontSuggestWildcardGenerics-out.java @@ -0,0 +1,16 @@ +class Main { + void foo(List<? extends Number> list) { + list.forEach(new Consumer<Number>() { + @Override + public void consume(Number number) { + <caret> + } + }); + } +} + +class List<T> { + void forEach(Consumer<? super T> consumer); +} + +interface Consumer<T> { void consume(T t); }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/DontSuggestWildcardGenerics.java b/java/java-tests/testData/codeInsight/completion/smartType/DontSuggestWildcardGenerics.java new file mode 100644 index 000000000000..b1d18904a6fb --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/DontSuggestWildcardGenerics.java @@ -0,0 +1,11 @@ +class Main { + void foo(List<? extends Number> list) { + list.forEach(new <caret>); + } +} + +class List<T> { + void forEach(Consumer<? super T> consumer); +} + +interface Consumer<T> { void consume(T t); }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferFieldsToConstants.java b/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferFieldsToConstants.java new file mode 100644 index 000000000000..2b47bb58a498 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferFieldsToConstants.java @@ -0,0 +1,17 @@ +public class Foo { + + private LocalDate dateField; + + void foo(LocalDate date) { + + } + + void bar() { + foo(<caret>) + } +} + +class LocalDate { + public static final LocalDate MAX; + public static final LocalDate MIN; +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/PolymorphicTypeCast.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/PolymorphicTypeCast.java index 8be16fc1db85..8ba3ea4f8037 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/PolymorphicTypeCast.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/PolymorphicTypeCast.java @@ -94,4 +94,96 @@ class C { void asLongs(Integer i) { long l = (long) i; } + + void foo(Object o) {} + public void cast2(Byte operand) { + foo((<warning descr="Casting 'operand' to 'byte' is redundant">byte</warning>)operand); + foo((short)operand); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Byte' to 'char'">(char)operand</error>); + foo((int)operand); + foo((long)operand); + foo((float)operand); + foo((double)operand); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Byte' to 'boolean'">(boolean)operand</error>); + } + public void cast2(Short operand) { + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Short' to 'byte'">(byte)operand</error>); + foo((<warning descr="Casting 'operand' to 'short' is redundant">short</warning>)operand); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Short' to 'char'">(char)operand</error>); + foo((int)operand); + foo((long)operand); + foo((float)operand); + foo((double)operand); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Short' to 'boolean'">(boolean)operand</error>); + } + public void cast2(Character operand) { + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Character' to 'byte'">(byte)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Character' to 'short'">(short)operand</error>); + foo((<warning descr="Casting 'operand' to 'char' is redundant">char</warning>)operand); + foo((int)operand); + foo((long)operand); + foo((float)operand); + foo((double)operand); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Character' to 'boolean'">(boolean)operand</error>); + } + public void cast2(Integer operand) { + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Integer' to 'byte'">(byte)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Integer' to 'short'">(short)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Integer' to 'char'">(char)operand</error>); + foo((<warning descr="Casting 'operand' to 'int' is redundant">int</warning>)operand); + foo((long)operand); + foo((float)operand); + foo((double)operand); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Integer' to 'boolean'">(boolean)operand</error>); + } + public void cast2(Long operand) { + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Long' to 'byte'">(byte)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Long' to 'short'">(short)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Long' to 'char'">(char)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Long' to 'int'">(int)operand</error>); + foo((<warning descr="Casting 'operand' to 'long' is redundant">long</warning>)operand); + foo((float)operand); + foo((double)operand); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Long' to 'boolean'">(boolean)operand</error>); + } + public void cast2(Float operand) { + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Float' to 'byte'">(byte)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Float' to 'short'">(short)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Float' to 'char'">(char)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Float' to 'int'">(int)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Float' to 'long'">(long)operand</error>); + foo((<warning descr="Casting 'operand' to 'float' is redundant">float</warning>)operand); + foo((double)operand); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Float' to 'boolean'">(boolean)operand</error>); + } + public void cast2(Double operand) { + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Double' to 'byte'">(byte)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Double' to 'short'">(short)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Double' to 'char'">(char)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Double' to 'int'">(int)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Double' to 'long'">(long)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Double' to 'float'">(float)operand</error>); + foo((<warning descr="Casting 'operand' to 'double' is redundant">double</warning>)operand); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Double' to 'boolean'">(boolean)operand</error>); + } + public void cast2(Boolean operand) { + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Boolean' to 'byte'">(byte)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Boolean' to 'short'">(short)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Boolean' to 'char'">(char)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Boolean' to 'int'">(int)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Boolean' to 'long'">(long)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Boolean' to 'float'">(float)operand</error>); + foo(<error descr="Inconvertible types; cannot cast 'java.lang.Boolean' to 'double'">(double)operand</error>); + foo((<warning descr="Casting 'operand' to 'boolean' is redundant">boolean</warning>)operand); + } + public void cast2(Object operand) { + foo((<warning descr="Casting 'operand' to 'byte' is redundant">byte</warning>)operand); + foo((<warning descr="Casting 'operand' to 'short' is redundant">short</warning>)operand); + foo((<warning descr="Casting 'operand' to 'char' is redundant">char</warning>)operand); + foo((<warning descr="Casting 'operand' to 'int' is redundant">int</warning>)operand); + foo((<warning descr="Casting 'operand' to 'long' is redundant">long</warning>)operand); + foo((<warning descr="Casting 'operand' to 'float' is redundant">float</warning>)operand); + foo((<warning descr="Casting 'operand' to 'double' is redundant">double</warning>)operand); + foo((<warning descr="Casting 'operand' to 'boolean' is redundant">boolean</warning>)operand); + } }
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128101.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128101.java new file mode 100644 index 000000000000..42be49b62f04 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128101.java @@ -0,0 +1,29 @@ +class TestIDEA128101 { + + static class Attribute<Y> {}; + static class Path<X> {}; + + static Attribute<Integer> integerAttribute; + static Attribute<String> stringAttribute; + + static <Y> Path<Y> createPath(Attribute<Y> attribute) { + return new Path<>(); + } + static <Y> Path<Y> createPath1(Attribute<Y> attribute) { + return new Path<>(); + } + static <T> void construct(Class<T> aClass, Path<?>... paths) {} + static <T, K> void construct1(Class<T> aClass, Path<K>... paths) {} + static <T, K> void construct2(Class<T> aClass, Path<? extends K>... paths) {} + static <T, K> void construct3(Class<T> aClass, Path<? super K>... paths) {} + static <T, K> void construct4(Class<T> aClass, Path<? super K> path1, Path<? super K> path2) {} + + public static void test() { + construct(String.class, createPath(integerAttribute), createPath(stringAttribute)); + construct1<error descr="Cannot resolve method 'construct1(java.lang.Class<java.lang.String>, TestIDEA128101.Path<java.lang.Integer>, TestIDEA128101.Path<java.lang.String>)'">(String.class, createPath(integerAttribute), createPath(stringAttribute))</error>; + construct2(String.class, createPath(integerAttribute), createPath(stringAttribute)); + <error descr="Type parameter K has incompatible upper bounds: Integer and String">construct3(String.class, createPath(integerAttribute), createPath(stringAttribute));</error> + <error descr="Type parameter K has incompatible upper bounds: Integer and String">construct4(String.class, createPath(integerAttribute), createPath(stringAttribute));</error> + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128174.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128174.java new file mode 100644 index 000000000000..650114b06e50 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IDEA128174.java @@ -0,0 +1,24 @@ +import java.util.Collection; +import java.util.List; + +class Test { + + { + Matcher<? super List<String>> m = not(empty()); + } + + static <E> Matcher<Collection<E>> empty() { + return null; + } + + static <T> Matcher<T> not(Matcher<T> matcher) { + return null; + } + + static <T> Matcher<T> not(T value) { + return null; + } + + static class Matcher<K> {} +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/InferFromConditionalExpressionCondition.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/InferFromConditionalExpressionCondition.java new file mode 100644 index 000000000000..8fad96c118ed --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/InferFromConditionalExpressionCondition.java @@ -0,0 +1,14 @@ +class Test { + static class TKey<T> { + } + + public interface Getter { + <T> T getValue(TKey<T> key); + } + + static final TKey<Boolean> KEY_B = new TKey<>(); + + public static void f(Getter getter) { + String name = getter.getValue(KEY_B) ? "foo" : "bar"; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/PrimitiveWrapperConditionInReturnConstraint.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/PrimitiveWrapperConditionInReturnConstraint.java new file mode 100644 index 000000000000..6788a98b215c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/PrimitiveWrapperConditionInReturnConstraint.java @@ -0,0 +1,15 @@ +class Test { + static class TKey<T> { + } + + public interface Getter { + <T> T getValue(TKey<T> key); + } + + static final TKey<Integer> KEY_I = null; + + + public static void f(Getter getter, TKey<Integer> key) { + double d1 = getter.getValue (key); + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java index 254ec7191a47..92b268394994 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java @@ -39,7 +39,7 @@ public class XXX { void m3(int x, boolean cond) { int y; if (cond) y = 1; - foo(() -> x+<error descr="Variable used in lambda expression should be effectively final">y</error>); + foo(() -> x+<error descr="Variable 'y' might not have been initialized">y</error>); } void m4(int x, boolean cond) { @@ -128,3 +128,17 @@ class IDEA114737 { }; } } + +class IDEA128196 { + void a() { + int value; + + try { + value = 1; + } catch (Exception e) { + return; + } + + new Thread(() -> System.out.println(value)); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/IDEA127765.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/IDEA127765.java new file mode 100644 index 000000000000..095448e262b3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/IDEA127765.java @@ -0,0 +1,19 @@ +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Predicate; + +class IDEA127765 { + void a(final Map<String, Optional<Double>> allValues, final Function<Optional<Double>, Double> get) { + final Map<String, Double> presentValues = transformValues(filterValues(allValues, Optional::isPresent), get); + } + + public static <K, V1, V2> Map<K, V2> transformValues(Map<K, V1> fromMap, Function<? super V1, V2> function) { + return null; + } + + public static <K, V> Map<K, V> filterValues(Map<K, V> unfiltered, Predicate<? super V> valuePredicate) { + return null; + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterOnVarargsPlace.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterOnVarargsPlace.java new file mode 100644 index 000000000000..82e3cc9aa3e6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterOnVarargsPlace.java @@ -0,0 +1,10 @@ +// "Replace with lambda" "true" +class Test2 { + + void f(Runnable... rs){} + { + f(null, () -> { + + }); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeOnVarargsPlace.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeOnVarargsPlace.java new file mode 100644 index 000000000000..af9db7767997 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeOnVarargsPlace.java @@ -0,0 +1,13 @@ +// "Replace with lambda" "true" +class Test2 { + + void f(Runnable... rs){} + { + f(null, new Run<caret>nable() { + @Override + public void run() { + + } + }); + } +} diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/null/singleExclamationIgnored.java b/java/java-tests/testData/codeInsight/template/postfix/templates/null/singleExclamationIgnored.java new file mode 100644 index 000000000000..1af8cd0813a9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/null/singleExclamationIgnored.java @@ -0,0 +1,5 @@ +public class Foo { + void m(Object o) { + !.null<caret> + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/null/singleExclamationIgnored_after.java b/java/java-tests/testData/codeInsight/template/postfix/templates/null/singleExclamationIgnored_after.java new file mode 100644 index 000000000000..1334be6b7029 --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/null/singleExclamationIgnored_after.java @@ -0,0 +1,5 @@ +public class Foo { + void m(Object o) { + !.null <caret> + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/typing/invalidInitialSyntax_after.java b/java/java-tests/testData/codeInsight/typing/invalidInitialSyntax_after.java new file mode 100644 index 000000000000..08b2afd09cb9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/typing/invalidInitialSyntax_after.java @@ -0,0 +1,7 @@ +class Foo { + public static void main(String[] args) { + String s = ""; + s.replaceAll("\\<caret>"); + System.out.println(); + } +} diff --git a/java/java-tests/testData/codeInsight/typing/invalidInitialSyntax_before.java b/java/java-tests/testData/codeInsight/typing/invalidInitialSyntax_before.java new file mode 100644 index 000000000000..bee6f10053c2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/typing/invalidInitialSyntax_before.java @@ -0,0 +1,7 @@ +class Foo { + public static void main(String[] args) { + String s = ""; + s.replaceAll("<caret>"); + System.out.println(); + } +} diff --git a/java/java-tests/testData/find/findInEditor/BasicFind.gold b/java/java-tests/testData/find/findInEditor/BasicFind.gold index 14e4182499b7..46486765486d 100644 --- a/java/java-tests/testData/find/findInEditor/BasicFind.gold +++ b/java/java-tests/testData/find/findInEditor/BasicFind.gold @@ -3,8 +3,7 @@ myStringToFind =a myStringToReplace = isReplaceState =false isWholeWordsOnly =false -isInStringLiterals =false -isInComments =false +searchContext =ANY isFromCursor =true isForward =true isGlobal =true @@ -22,6 +21,7 @@ isWithSubdirectories =true fileFilter =null moduleName =null customScopeName =null +searchInProjectFiles =false -- diff --git a/java/java-tests/testData/find/findInEditor/EmacsLikeFallback.gold b/java/java-tests/testData/find/findInEditor/EmacsLikeFallback.gold index a2168ba66e2a..bfda616a3ac1 100644 --- a/java/java-tests/testData/find/findInEditor/EmacsLikeFallback.gold +++ b/java/java-tests/testData/find/findInEditor/EmacsLikeFallback.gold @@ -3,8 +3,7 @@ myStringToFind =a myStringToReplace = isReplaceState =false isWholeWordsOnly =false -isInStringLiterals =false -isInComments =false +searchContext =ANY isFromCursor =true isForward =true isGlobal =true @@ -22,6 +21,7 @@ isWithSubdirectories =true fileFilter =null moduleName =null customScopeName =null +searchInProjectFiles =false -- @@ -37,8 +37,7 @@ myStringToFind =ab myStringToReplace = isReplaceState =false isWholeWordsOnly =false -isInStringLiterals =false -isInComments =false +searchContext =ANY isFromCursor =true isForward =true isGlobal =true @@ -56,6 +55,7 @@ isWithSubdirectories =true fileFilter =null moduleName =null customScopeName =null +searchInProjectFiles =false -- @@ -70,8 +70,7 @@ myStringToFind =a myStringToReplace = isReplaceState =false isWholeWordsOnly =false -isInStringLiterals =false -isInComments =false +searchContext =ANY isFromCursor =true isForward =true isGlobal =true @@ -89,6 +88,7 @@ isWithSubdirectories =true fileFilter =null moduleName =null customScopeName =null +searchInProjectFiles =false -- diff --git a/java/java-tests/testData/find/findInEditor/ReplacementWithEmptyString.gold b/java/java-tests/testData/find/findInEditor/ReplacementWithEmptyString.gold index 478eb649684d..a4d44cbfa445 100644 --- a/java/java-tests/testData/find/findInEditor/ReplacementWithEmptyString.gold +++ b/java/java-tests/testData/find/findInEditor/ReplacementWithEmptyString.gold @@ -3,8 +3,7 @@ myStringToFind = myStringToReplace = isReplaceState =false isWholeWordsOnly =false -isInStringLiterals =false -isInComments =false +searchContext =ANY isFromCursor =true isForward =true isGlobal =true @@ -22,6 +21,7 @@ isWithSubdirectories =true fileFilter =null moduleName =null customScopeName =null +searchInProjectFiles =false -- @@ -33,8 +33,7 @@ myStringToFind =a myStringToReplace = isReplaceState =false isWholeWordsOnly =false -isInStringLiterals =false -isInComments =false +searchContext =ANY isFromCursor =true isForward =true isGlobal =true @@ -52,6 +51,7 @@ isWithSubdirectories =true fileFilter =null moduleName =null customScopeName =null +searchInProjectFiles =false -- @@ -65,8 +65,7 @@ myStringToFind =a myStringToReplace = isReplaceState =true isWholeWordsOnly =false -isInStringLiterals =false -isInComments =false +searchContext =ANY isFromCursor =true isForward =true isGlobal =true @@ -84,6 +83,7 @@ isWithSubdirectories =true fileFilter =null moduleName =null customScopeName =null +searchInProjectFiles =false -- Replacement Preview: <Empty string> @@ -99,8 +99,7 @@ myStringToFind =a myStringToReplace = isReplaceState =true isWholeWordsOnly =false -isInStringLiterals =false -isInComments =false +searchContext =ANY isFromCursor =true isForward =true isGlobal =true @@ -118,6 +117,7 @@ isWithSubdirectories =true fileFilter =null moduleName =null customScopeName =null +searchInProjectFiles =false -- diff --git a/java/java-tests/testData/inspection/dataFlow/CheckedExceptionDominance/src/Test.java b/java/java-tests/testData/inspection/dataFlow/CheckedExceptionDominance/src/Test.java index 4a0a690f0e21..4f0586d30a96 100644 --- a/java/java-tests/testData/inspection/dataFlow/CheckedExceptionDominance/src/Test.java +++ b/java/java-tests/testData/inspection/dataFlow/CheckedExceptionDominance/src/Test.java @@ -19,6 +19,6 @@ } public static void bar() throws CheckedException { - throw new CheckedException(); + if (new Random().nextInt() > 2) throw new CheckedException(); } } diff --git a/java/java-tests/testData/inspection/dataFlow/IDEADEV10489/expected.xml b/java/java-tests/testData/inspection/dataFlow/IDEADEV10489/expected.xml index bb6256f74012..4a088210968c 100644 --- a/java/java-tests/testData/inspection/dataFlow/IDEADEV10489/expected.xml +++ b/java/java-tests/testData/inspection/dataFlow/IDEADEV10489/expected.xml @@ -7,7 +7,7 @@ </problem> <problem> <file>IDEADEV10489.java</file> - <line>12</line> + <line>8</line> <description>Method invocation 's.length()' may produce NullPointerException</description> </problem> </problems>
\ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/IDEADEV10489/src/IDEADEV10489.java b/java/java-tests/testData/inspection/dataFlow/IDEADEV10489/src/IDEADEV10489.java index 60259479d353..ee41e588dd3e 100644 --- a/java/java-tests/testData/inspection/dataFlow/IDEADEV10489/src/IDEADEV10489.java +++ b/java/java-tests/testData/inspection/dataFlow/IDEADEV10489/src/IDEADEV10489.java @@ -1,7 +1,5 @@ class IDEADEV10489 { - static String getS() { - return null; - } + static native String getS(); static void f() { String s = getS(); @@ -17,7 +15,5 @@ class IDEADEV10489 { } } - private static boolean foo() { - return false; - } + private static native boolean foo(); }
\ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/AssertFailInCatch.java b/java/java-tests/testData/inspection/dataFlow/fixture/AssertFailInCatch.java index 93fcf6d5c2d2..55c7c2b51de0 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/AssertFailInCatch.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/AssertFailInCatch.java @@ -18,7 +18,5 @@ class Test { } } - private static @NotNull String createString() { - throw new NullPointerException(); - } + private static native @NotNull String createString(); }
\ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/CatchThrowable.java b/java/java-tests/testData/inspection/dataFlow/fixture/CatchThrowable.java index ecb9b264bb62..a30d934f64b6 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/CatchThrowable.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/CatchThrowable.java @@ -1,3 +1,5 @@ +import java.util.Random; + class BrokenAlignment { public static void main(String[] args) { @@ -20,7 +22,7 @@ class BrokenAlignment { } public static void doSomething() { - throw new RuntimeException("dummy"); + if (new Random().nextInt() > 2) throw new RuntimeException("dummy"); } }
\ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ContractWithNoArgs.java b/java/java-tests/testData/inspection/dataFlow/fixture/ContractWithNoArgs.java new file mode 100644 index 000000000000..006c2e3407ec --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ContractWithNoArgs.java @@ -0,0 +1,24 @@ +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class Doo { + + @NotNull + public String doSomething() { + String s = getSomeString(); + if (s == null) { + throwSomeError(); + } + return s; + } + + private static void throwSomeError() { + throw new RuntimeException(); + } + + @Nullable + public String getSomeString() { + return Math.random() > 0.5 ? null : "Yeah"; + } + +} diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/CustomTypeQualifierDefault.java b/java/java-tests/testData/inspection/dataFlow/fixture/CustomTypeQualifierDefault.java new file mode 100644 index 000000000000..e9ec6b1dbe11 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/CustomTypeQualifierDefault.java @@ -0,0 +1,25 @@ +import foo.*; +import org.jetbrains.annotations.NotNull; + +class Some { + void foo(@NotNull String s) { + NotNullClass.foo(null); + if (<warning descr="Condition 'NotNullClass.foo(s) == null' is always 'false'">NotNullClass.foo(s) == null</warning>) {} + + NullableClass.foo(null); + if (NullableClass.foo("a") == null) {} + + AnotherPackageNotNull.foo(null); + if (<warning descr="Condition 'AnotherPackageNotNull.foo(s) == null' is always 'false'">AnotherPackageNotNull.foo(s) == null</warning>) {} + } + +} + +@bar.MethodsAreNotNullByDefault +class NotNullClass { + static native Object foo(String s); + +} +class NullableClass { + static native Object foo(String s); +}
\ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/FloatComparisons.java b/java/java-tests/testData/inspection/dataFlow/fixture/FloatComparisons.java new file mode 100644 index 000000000000..5c553bcba0bf --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/FloatComparisons.java @@ -0,0 +1,7 @@ +class Test { + public static void testFunc(final float width, final float height) { + if (width < 0f || height < 0f) { + throw new IllegalArgumentException("Size must be non-negative"); + } + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/refactoring/renameCollisions/RenameMethodNoCollisionWithOtherSignatureMethodRef.java b/java/java-tests/testData/refactoring/renameCollisions/RenameMethodNoCollisionWithOtherSignatureMethodRef.java new file mode 100644 index 000000000000..dd815139efa5 --- /dev/null +++ b/java/java-tests/testData/refactoring/renameCollisions/RenameMethodNoCollisionWithOtherSignatureMethodRef.java @@ -0,0 +1,9 @@ +class Test { + + static void f<caret>oo() {} + static void foo2(int i) {} + + { + Runnable r = Test :: foo; + } +}
\ No newline at end of file diff --git a/java/java-tests/testData/refactoring/renameCollisions/RenameMethodNoCollisionWithOtherSignatureMethodRef.java.after b/java/java-tests/testData/refactoring/renameCollisions/RenameMethodNoCollisionWithOtherSignatureMethodRef.java.after new file mode 100644 index 000000000000..8dab0803fcec --- /dev/null +++ b/java/java-tests/testData/refactoring/renameCollisions/RenameMethodNoCollisionWithOtherSignatureMethodRef.java.after @@ -0,0 +1,9 @@ +class Test { + + static void foo2() {} + static void foo2(int i) {} + + { + Runnable r = Test ::foo2; + } +}
\ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java index ae0ec20ab4d2..8383550b3e5c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java @@ -20,6 +20,8 @@ import com.intellij.pom.java.LanguageLevel; public class ClsGenerics18HighlightingTest extends ClsGenericsHighlightingTest { public void testIDEA121866() { doTest(); } + public void testIDEA127714() { doTest(); } + @Override protected LanguageLevel getLanguageLevel() { return LanguageLevel.JDK_1_8; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java index 2eecdaa9b221..3f199d44ea13 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java @@ -17,9 +17,6 @@ package com.intellij.codeInsight; import com.intellij.JavaTestUtil; import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.roots.LanguageLevelProjectExtension; -import com.intellij.pom.java.LanguageLevel; -import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; @@ -54,6 +51,18 @@ public class CompleteStatementTest extends EditorActionTestCase { public void testCompleteCatchLParen() throws Exception { doTest(); } + public void testAlreadyCompleteCatch() throws Exception { + CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); + int old = settings.BRACE_STYLE; + settings.BRACE_STYLE = CommonCodeStyleSettings.NEXT_LINE; + try { + doTest(); + } + finally { + settings.BRACE_STYLE = old; + } + } + public void testCompleteCatchWithExpression() throws Exception { doTest(); } public void testCompleteCatchBody() throws Exception { doTest(); } @@ -171,8 +180,6 @@ public class CompleteStatementTest extends EditorActionTestCase { } public void testSCR36110() throws Exception { - JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject()); - LanguageLevel old = LanguageLevelProjectExtension.getInstance(facade.getProject()).getLanguageLevel(); doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/JavaTypingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/JavaTypingTest.java index f59162a6d5b2..9ca3b6084a43 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/JavaTypingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/JavaTypingTest.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight; import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.psi.PsiDocumentManager; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; @@ -65,6 +66,14 @@ public class JavaTypingTest extends LightPlatformCodeInsightFixtureTestCase { myFixture.checkResultByFile(getTestName(true) + "_after.java"); } + public void testInvalidInitialSyntax() { + myFixture.configureByFile(getTestName(true) + "_before.java"); + myFixture.type('\\'); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); // emulates background commit after typing first character + myFixture.type('\\'); + myFixture.checkResultByFile(getTestName(true) + "_after.java"); + } + private void doTest(char c) { myFixture.configureByFile(getTestName(true) + "_before.java"); myFixture.type(c); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index 77b4c0cc64a7..f5fc39041106 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -1423,6 +1423,11 @@ class XInternalError {} checkResult() } + public void testMulticaretCompletionFromNonPrimaryCaret() { + configure() + myFixture.assertPreferredCompletionItems(0, "arraycopy") + } + public void "test complete lowercase class name"() { myFixture.addClass("package foo; public class myClass {}") myFixture.configureByText "a.java", """ diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy index 1d258fe01367..f37b90e21523 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy @@ -160,6 +160,10 @@ public class SmartTypeCompletionOrderingTest extends CompletionSortingTestCase { checkPreferredItems(0, "myVersion", "getVersion", "getSelectedVersion", "calculateVersion"); } + public void testPreferFieldsToConstants() { + checkPreferredItems(0, "dateField", "LocalDate.MAX", "LocalDate.MIN"); + } + public void testPreferParametersToGetters() throws Throwable { checkPreferredItems(0, "a", "I._1", "getLastI", "valueOf"); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index d2e8825cc16d..5153f19fe94a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -716,7 +716,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { public void testMethodColon() throws Exception { doFirstItemTest(':'); } public void testVariableColon() throws Exception { doFirstItemTest(':'); } - private void doFirstItemTest(char c) throws Exception { + private void doFirstItemTest(char c) { configureByTestName(); select(c); checkResultByTestName(); @@ -824,6 +824,8 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { doActionTest(); } + public void testDontSuggestWildcardGenerics() { doItemTest(); } + public void testCastWith2TypeParameters() throws Throwable { doTest(); } public void testClassLiteralInArrayAnnoInitializer() throws Throwable { doTest(); } public void testClassLiteralInArrayAnnoInitializer2() throws Throwable { doTest(); } @@ -1141,7 +1143,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { checkResultByTestName(); } - private void doItemTest() throws Exception { + private void doItemTest() { doFirstItemTest('\n'); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index 79506280a778..6ccefa35ae51 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -188,6 +188,22 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } + public void testInferFromConditionalExpressionCondition() throws Exception { + doTest(); + } + + public void testPrimitiveWrapperConditionInReturnConstraint() throws Exception { + doTest(); + } + + public void testIDEA128174() throws Exception { + doTest(); + } + + public void testIDEA128101() throws Exception { + doTest(); + } + private void doTest() throws Exception { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java index fbf8036e8e35..156aac5613c1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java @@ -106,6 +106,10 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testIDEA127765() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingGotoTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingGotoTest.java new file mode 100644 index 000000000000..b94e54d91323 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingGotoTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2014 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.codeInsight.folding; + +import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ex.FoldingModelEx; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; + +public class JavaFoldingGotoTest extends JavaCodeInsightFixtureTestCase { + + public void testIDEA127145() { + PsiFile file = myFixture.addFileToProject("Program.java", + "import java.io.InputStream;\n" + + "import java.util.HashMap;\n" + + "import java.util.Map;\n" + + "\n" + + "class Program {\n" + + " private static InputStream getFile(String name, Map<String, Object> args) {\n" + + " return Program.class.getResourceAsStream(name);\n" + + " }\n" + + "\n" + + " public static void main(String[] args) {\n" + + " // Ctrl + B or Ctrl + Left Mouse Button work correctly for following string:\n" + + " final String name = \"file.sql\";\n" + + " // But it jumps only to folder in following case:\n" + + " final InputStream inputStream = getFile(\"dir/fil<caret>e.sql\", new HashMap<String, Object>());\n" + + " }\n" + + "}"); + + PsiFile fileSql = myFixture.addFileToProject("dir/file.sql", "select 1;"); + myFixture.configureFromExistingVirtualFile(file.getVirtualFile()); + + Editor editor = myFixture.getEditor(); + CodeFoldingManager.getInstance(getProject()).buildInitialFoldings(editor); + FoldingModelEx foldingModel = (FoldingModelEx)editor.getFoldingModel(); + foldingModel.rebuild(); + myFixture.doHighlighting(); + + PsiElement element = GotoDeclarationAction.findTargetElement(getProject(), editor, editor.getCaretModel().getOffset()); + assertTrue("Should navigate to: file.sql instead of " + element, element != null && element.equals(fileSql)); + } + +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy index 5d823e001f82..095de51543af 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy @@ -568,14 +568,20 @@ class Test { public void "test fold one-line methods"() { configure """class Foo { + @Override int someMethod() { return 0; } + int someOtherMethod( + int param) { + return 0; + } + }""" PsiClass fooClass = JavaPsiFacade.getInstance(project).findClass('Foo', GlobalSearchScope.allScope(project)) def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } - assert regions.size() == 2 + assert regions.size() == 3 checkAccessorFolding(regions[0], regions[1], fooClass.methods[0]) } @@ -792,13 +798,14 @@ public class CharSymbol { assert regions[3].placeholderText == 'seq: "Hi!"' } - public void "test inline negative numbers (IDEA-126753)"() { + public void "test inline negative and positive numbers"() { def text = """ public class CharSymbol { public void main() { Object obj = new Object(); count(-1, obj); + count(+1, obj); } public void count(int test, Object obj) { @@ -809,10 +816,13 @@ public class CharSymbol { """ configure text def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } - assert regions.size() == 3 + assert regions.size() == 4 checkRangeOffsetByPositionInText(regions[1], text, "-1") assert regions[1].placeholderText == "test: -1" + + checkRangeOffsetByPositionInText(regions[2], text, "+1") + assert regions[2].placeholderText == "test: +1" } public void "test inline constructor literal arguments names"() { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/NullPostfixTemplateTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/NullPostfixTemplateTest.java index 7f47795881bc..70061e56afa9 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/NullPostfixTemplateTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/NullPostfixTemplateTest.java @@ -38,4 +38,9 @@ public class NullPostfixTemplateTest extends PostfixTemplateTestCase { public void testSecondStatement() { doTest(); } + + + public void testSingleExclamationIgnored() { + doTest(); + } }
\ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy b/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy index 23eac589e2db..89762efe5dd2 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy @@ -228,6 +228,34 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase { assert c == [] } + public void "test boolean autoboxing in delegation"() { + def c = inferContracts(""" + static Boolean test04(String s) { + return test03(s); + } + static boolean test03(String s) { + return s == null; + } + """) + assert c == [] + } + + public void "test boolean auto-unboxing"() { + def c = inferContracts(""" + static boolean test02(String s) { + return test01(s); + } + + static Boolean test01(String s) { + if (s == null) + return new Boolean(false); + else + return null; + } + """) + assert c == [] + } + public void "test non-returning delegation"() { def c = inferContracts(""" static void test2(Object o) { diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index 4cba2ab918a7..33eb32eb0ec6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -18,6 +18,7 @@ package com.intellij.codeInspection; import com.intellij.JavaTestUtil; import com.intellij.codeInspection.dataFlow.DataFlowInspection; import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import org.jetbrains.annotations.NotNull; @@ -251,15 +252,17 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { public void testRootThrowableCause() { doTest(); } public void testUseInferredContracts() { doTest(); } + public void testContractWithNoArgs() { doTest(); } public void testContractInferenceBewareOverriding() { doTest(); } public void testNumberComparisonsWhenValueIsKnown() { doTest(); } + public void testFloatComparisons() { doTest(); } public void testAccessingSameArrayElements() { doTest(); } public void testParametersAreNonnullByDefault() { - myFixture.addClass("package javax.annotation; public @interface ParametersAreNonnullByDefault {}"); - myFixture.addClass("package javax.annotation; public @interface ParametersAreNullableByDefault {}"); + addJavaxNullabilityAnnotations(myFixture); + addJavaxDefaultNullabilityAnnotations(myFixture); myFixture.addClass("package foo; public class AnotherPackageNotNull { public static void foo(String s) {}}"); myFixture.addFileToProject("foo/package-info.java", "@javax.annotation.ParametersAreNonnullByDefault package foo;"); @@ -267,6 +270,37 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { doTest(); } + public static void addJavaxDefaultNullabilityAnnotations(final JavaCodeInsightTestFixture fixture) { + fixture.addClass("package javax.annotation;" + + "@javax.annotation.meta.TypeQualifierDefault(java.lang.annotation.ElementType.PARAMETER) @javax.annotation.Nonnull " + + "public @interface ParametersAreNonnullByDefault {}"); + fixture.addClass("package javax.annotation;" + + "@javax.annotation.meta.TypeQualifierDefault(java.lang.annotation.ElementType.PARAMETER) @javax.annotation.Nullable " + + "public @interface ParametersAreNullableByDefault {}"); + } + + public static void addJavaxNullabilityAnnotations(final JavaCodeInsightTestFixture fixture) { + fixture.addClass("package javax.annotation;" + + "public @interface Nonnull {}"); + fixture.addClass("package javax.annotation;" + + "public @interface Nullable {}"); + fixture.addClass("package javax.annotation.meta;" + + "public @interface TypeQualifierDefault { java.lang.annotation.ElementType[] value() default {};}"); + } + + public void testCustomTypeQualifierDefault() { + addJavaxNullabilityAnnotations(myFixture); + myFixture.addClass("package bar;" + + "@javax.annotation.meta.TypeQualifierDefault(java.lang.annotation.ElementType.METHOD) @javax.annotation.Nonnull " + + "public @interface MethodsAreNotNullByDefault {}"); + + myFixture.addClass("package foo; public class AnotherPackageNotNull { public static native Object foo(String s); }"); + myFixture.addFileToProject("foo/package-info.java", "@bar.MethodsAreNotNullByDefault package foo;"); + + myFixture.enableInspections(new DataFlowInspection()); + myFixture.testHighlighting(true, false, true, getTestName(false) + ".java"); + } + public void testTrueOrEqualsSomething() { doTest(); myFixture.launchAction(myFixture.findSingleIntention("Remove redundant assignment")); diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java index e925dd49a8ea..3520ec08d750 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java @@ -40,8 +40,8 @@ public class NullableStuffInspectionTest extends LightCodeInsightFixtureTestCase } public void testHonorSuperParameterDefault() { - myFixture.addClass("package javax.annotation; public @interface ParametersAreNonnullByDefault {}"); - myFixture.addClass("package javax.annotation; public @interface Nullable {}"); + DataFlowInspectionTest.addJavaxNullabilityAnnotations(myFixture); + DataFlowInspectionTest.addJavaxDefaultNullabilityAnnotations(myFixture); myFixture.addFileToProject("foo/package-info.java", "@javax.annotation.ParametersAreNonnullByDefault package foo;"); myFixture.addClass("import javax.annotation.*; package foo; public interface NullableFunction { void fun(@Nullable Object o); }"); @@ -51,7 +51,8 @@ public class NullableStuffInspectionTest extends LightCodeInsightFixtureTestCase } public void testHonorThisParameterDefault() { - myFixture.addClass("package javax.annotation; public @interface ParametersAreNonnullByDefault {}"); + DataFlowInspectionTest.addJavaxNullabilityAnnotations(myFixture); + DataFlowInspectionTest.addJavaxDefaultNullabilityAnnotations(myFixture); myFixture.addFileToProject("foo/package-info.java", "@javax.annotation.ParametersAreNonnullByDefault package foo;"); myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject(getTestName(false) + ".java", "foo/Classes.java")); @@ -60,8 +61,8 @@ public class NullableStuffInspectionTest extends LightCodeInsightFixtureTestCase } public void testHonorParameterDefaultInSetters() { - myFixture.addClass("package javax.annotation; public @interface ParametersAreNonnullByDefault {}"); - myFixture.addClass("package javax.annotation; public @interface Nullable {}"); + DataFlowInspectionTest.addJavaxNullabilityAnnotations(myFixture); + DataFlowInspectionTest.addJavaxDefaultNullabilityAnnotations(myFixture); myFixture.addFileToProject("foo/package-info.java", "@javax.annotation.ParametersAreNonnullByDefault package foo;"); myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject(getTestName(false) + ".java", "foo/Classes.java")); diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java index 09fa87fa95e9..9d26fd804f68 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java @@ -183,7 +183,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase { private void checkCompoundId(Method method, PsiMethod psiMethod, boolean noKey) throws IOException { Direction direction = new Out(); - int psiKey = myBytecodeAnalysisConverter.mkPsiKey(psiMethod, direction); + long psiKey = myBytecodeAnalysisConverter.mkPsiKey(psiMethod, direction); if (noKey) { assertTrue(-1 == psiKey); return; @@ -192,7 +192,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase { assertFalse(-1 == psiKey); } - int asmKey = myBytecodeAnalysisConverter.mkAsmKey(new Key(method, direction, true)); + long asmKey = myBytecodeAnalysisConverter.mkAsmKey(new Key(method, direction, true)); Assert.assertEquals(asmKey, psiKey); } diff --git a/java/java-tests/testSrc/com/intellij/find/FindInEditorMultiCaretTest.java b/java/java-tests/testSrc/com/intellij/find/FindInEditorMultiCaretTest.java index 02f8c589c43b..3cc6c19618a1 100644 --- a/java/java-tests/testSrc/com/intellij/find/FindInEditorMultiCaretTest.java +++ b/java/java-tests/testSrc/com/intellij/find/FindInEditorMultiCaretTest.java @@ -19,7 +19,9 @@ import com.intellij.find.editorHeaderActions.*; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.util.Getter; +import com.intellij.testFramework.fixtures.EditorMouseFixture; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; import javax.swing.text.JTextComponent; @@ -58,7 +60,7 @@ public class FindInEditorMultiCaretTest extends LightPlatformCodeInsightFixtureT assertNull(getEditorSearchComponent()); } - public void testActionsWorkFromEditor() throws IOException { + public void testActionsInEditorWorkIndependently() throws IOException { init("abc\n" + "abc\n" + "abc"); @@ -67,27 +69,29 @@ public class FindInEditorMultiCaretTest extends LightPlatformCodeInsightFixtureT checkResultByText("a<selection>b<caret></selection>c\n" + "abc\n" + "abc"); + new EditorMouseFixture((EditorImpl)myFixture.getEditor()).clickAt(0, 1); addOccurrenceFromEditor(); - checkResultByText("a<selection>b<caret></selection>c\n" + - "a<selection>b<caret></selection>c\n" + + addOccurrenceFromEditor(); + checkResultByText("<selection>a<caret>bc</selection>\n" + + "<selection>a<caret>bc</selection>\n" + "abc"); nextOccurrenceFromEditor(); - checkResultByText("a<selection>b<caret></selection>c\n" + + checkResultByText("<selection>a<caret>bc</selection>\n" + "abc\n" + - "a<selection>b<caret></selection>c"); + "<selection>a<caret>bc</selection>"); prevOccurrenceFromEditor(); - checkResultByText("a<selection>b<caret></selection>c\n" + - "a<selection>b<caret></selection>c\n" + + checkResultByText("<selection>a<caret>bc</selection>\n" + + "<selection>a<caret>bc</selection>\n" + "abc"); removeOccurrenceFromEditor(); - checkResultByText("a<selection>b<caret></selection>c\n" + + checkResultByText("<selection>a<caret>bc</selection>\n" + "abc\n" + "abc"); allOccurrencesFromEditor(); - checkResultByText("a<selection>b<caret></selection>c\n" + - "a<selection>b<caret></selection>c\n" + - "a<selection>b<caret></selection>c"); - assertNull(getEditorSearchComponent()); + checkResultByText("<selection>a<caret>bc</selection>\n" + + "<selection>a<caret>bc</selection>\n" + + "<selection>a<caret>bc</selection>"); + assertNotNull(getEditorSearchComponent()); } public void testCloseRetainsMulticaretSelection() throws IOException { diff --git a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java index 92caad03d8ef..f83d836bb55a 100644 --- a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java +++ b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java @@ -579,7 +579,7 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { FindModel findModel = FindManagerTestUtils.configureFindModel("done"); String text = "/** done done done */"; - findModel.setInCommentsOnly(true); + findModel.setSearchContext(FindModel.SearchContext.IN_COMMENTS); FindManagerTestUtils.runFindForwardAndBackward(myFindManager, findModel, text); findModel.setRegularExpressions(true); @@ -592,7 +592,7 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { String prefix = "/*"; String text = prefix + "done*/"; - findModel.setInCommentsOnly(true); + findModel.setSearchContext(FindModel.SearchContext.IN_COMMENTS); LightVirtualFile file = new LightVirtualFile("A.java", text); FindResult findResult = myFindManager.findString(text, prefix.length(), findModel, file); @@ -615,8 +615,7 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { FindModel findModel = FindManagerTestUtils.configureFindModel("^done$"); findModel.setRegularExpressions(true); - findModel.setInStringLiteralsOnly(true); - findModel.setInCommentsOnly(false); + findModel.setSearchContext(FindModel.SearchContext.IN_STRING_LITERALS); String text = "\"done\"; 'done'; 'done' \"done2\""; FindManagerTestUtils.runFindForwardAndBackward(myFindManager, findModel, text, "java"); @@ -633,7 +632,7 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { String text = "/** do ne do ne do ne */"; - findModel.setInCommentsOnly(true); + findModel.setSearchContext(FindModel.SearchContext.IN_COMMENTS); FindManagerTestUtils.runFindForwardAndBackward(myFindManager, findModel, text, "java"); } @@ -651,4 +650,42 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { findModel.setWholeWordsOnly(true); assertSize(1, findUsages(findModel)); } + + public void testFindExceptComments() { + FindModel findModel = FindManagerTestUtils.configureFindModel("done"); + + String prefix = "/*"; + String text = prefix + "done*/done"; + + findModel.setSearchContext(FindModel.SearchContext.EXCEPT_COMMENTS); + LightVirtualFile file = new LightVirtualFile("A.java", text); + + FindResult findResult = myFindManager.findString(text, prefix.length(), findModel, file); + assertTrue(findResult.isStringFound()); + assertTrue(findResult.getStartOffset() > prefix.length()); + + findModel.setRegularExpressions(true); + findResult = myFindManager.findString(text, prefix.length(), findModel, file); + assertTrue(findResult.isStringFound()); + assertTrue(findResult.getStartOffset() > prefix.length()); + } + + public void testFindExceptLiterals() { + FindModel findModel = FindManagerTestUtils.configureFindModel("done"); + + String prefix = "\""; + String text = prefix + "done\"done"; + + findModel.setSearchContext(FindModel.SearchContext.EXCEPT_STRING_LITERALS); + LightVirtualFile file = new LightVirtualFile("A.java", text); + + FindResult findResult = myFindManager.findString(text, prefix.length(), findModel, file); + assertTrue(findResult.isStringFound()); + assertTrue(findResult.getStartOffset() > prefix.length()); + + findModel.setRegularExpressions(true); + findResult = myFindManager.findString(text, prefix.length(), findModel, file); + assertTrue(findResult.isStringFound()); + assertTrue(findResult.getStartOffset() > prefix.length()); + } } diff --git a/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy b/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy index dabe06ba79fa..9a97a825964a 100644 --- a/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy +++ b/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy @@ -24,7 +24,6 @@ import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import com.intellij.util.Consumer import com.intellij.util.concurrency.Semaphore import org.jetbrains.annotations.NotNull - /** * @author peter */ @@ -197,6 +196,33 @@ class Intf { assert getPopupElements(new GotoClassModel2(project), 'Bar:[2,3]') == [c] } + public void "test dollar"() { + def bar = myFixture.addClass("package foo; class Bar { class Foo {} }") + def foo = bar.innerClasses[0] + myFixture.addClass("package goo; class Goo { }") + assert getPopupElements(new GotoClassModel2(project), 'Bar$Foo') == [foo] + assert getPopupElements(new GotoClassModel2(project), 'foo.Bar$Foo') == [foo] + assert getPopupElements(new GotoClassModel2(project), 'foo.B$F') == [foo] + assert !getPopupElements(new GotoClassModel2(project), 'foo$Foo') + assert !getPopupElements(new GotoClassModel2(project), 'foo$Bar') + assert !getPopupElements(new GotoClassModel2(project), 'foo$Bar$Foo') + assert !getPopupElements(new GotoClassModel2(project), 'foo$Goo') + } + + public void "test anonymous classes"() { + def goo = myFixture.addClass("package goo; class Goo { Runnable r = new Runnable() {}; }") + assert getPopupElements(new GotoClassModel2(project), 'Goo$1') == [goo] + } + + public void "test qualified name matching"() { + def bar = myFixture.addClass("package foo.bar; class Bar { }") + def bar2 = myFixture.addClass("package goo.baz; class Bar { }") + assert getPopupElements(new GotoClassModel2(project), 'foo.Bar') == [bar] + assert getPopupElements(new GotoClassModel2(project), 'foo.bar.Bar') == [bar] + assert getPopupElements(new GotoClassModel2(project), 'goo.Bar') == [bar2] + assert getPopupElements(new GotoClassModel2(project), 'goo.baz.Bar') == [bar2] + } + public void "test super method in jdk"() { def ourRun = myFixture.addClass("package foo.bar; class Goo implements Runnable { public void run() {} }").methods[0] def sdkRun diff --git a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexTest.java b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexTest.java index 1e3e08a33ae7..56624594bb0e 100644 --- a/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexTest.java +++ b/java/java-tests/testSrc/com/intellij/openapi/roots/impl/DirectoryIndexTest.java @@ -49,7 +49,7 @@ import static java.util.Collections.singletonList; public class DirectoryIndexTest extends IdeaTestCase { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.DirectoryIndexTest"); - private DirectoryIndex myIndex; + private DirectoryIndexImpl myIndex; private Module myModule2, myModule3; private VirtualFile myRootVFile; @@ -65,6 +65,7 @@ public class DirectoryIndexTest extends IdeaTestCase { private VirtualFile myModule1OutputDir; private VirtualFile myResDir, myTestResDir; private VirtualFile myExcludedLibSrcDir, myExcludedLibClsDir; + private ProjectFileIndex myFileIndex; @Override protected void setUp() throws Exception { @@ -176,7 +177,8 @@ public class DirectoryIndexTest extends IdeaTestCase { } }); - myIndex = DirectoryIndex.getInstance(myProject); + myIndex = (DirectoryIndexImpl)DirectoryIndex.getInstance(myProject); + myFileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); // to not interfere with previous test firing vfs events VirtualFileManager.getInstance().syncRefresh(); } @@ -221,12 +223,12 @@ public class DirectoryIndexTest extends IdeaTestCase { VirtualFile cvs = myPack1Dir.createChildDirectory(this, "CVS"); assertNotInProject(cvs); - assertNull(ProjectRootManager.getInstance(myProject).getFileIndex().getPackageNameByDirectory(cvs)); + assertNull(myFileIndex.getPackageNameByDirectory(cvs)); } public void testDirsByPackageName() throws IOException { - checkPackage("", true, mySrcDir1, myTestSrc1, myResDir, myTestResDir, myFileLibSrc, myFileLibCls, mySrcDir2, myLibSrcDir, myLibClsDir); - checkPackage("", false, mySrcDir1, myTestSrc1, myResDir, myTestResDir, myFileLibCls, mySrcDir2, myLibClsDir); + checkPackage("", true, mySrcDir1, myTestSrc1, myResDir, myTestResDir, mySrcDir2, myLibSrcDir, myLibClsDir); + checkPackage("", false, mySrcDir1, myTestSrc1, myResDir, myTestResDir, mySrcDir2, myLibClsDir); checkPackage("pack1", true, myPack1Dir); checkPackage("pack1", false, myPack1Dir); @@ -257,6 +259,18 @@ public class DirectoryIndexTest extends IdeaTestCase { checkPackage("pack1", true, myPack1Dir, myModule3Dir); } + public void testPackageDirectoriesWithDots() throws IOException { + VirtualFile fooBar = mySrcDir1.createChildDirectory(this, "foo.bar"); + VirtualFile goo1 = fooBar.createChildDirectory(this, "goo"); + VirtualFile foo = mySrcDir2.createChildDirectory(this, "foo"); + VirtualFile bar = foo.createChildDirectory(this, "bar"); + VirtualFile goo2 = bar.createChildDirectory(this, "goo"); + + checkPackage("foo", false, foo); + checkPackage("foo.bar", false, bar, fooBar); + checkPackage("foo.bar.goo", false, goo2, goo1); + } + public void testCreateDir() throws Exception { String path = mySrcDir1.getPath().replace('/', File.separatorChar); assertTrue(new File(path + File.separatorChar + "dir1" + File.separatorChar + "dir2").mkdirs()); @@ -362,7 +376,8 @@ public class DirectoryIndexTest extends IdeaTestCase { VirtualFile ignoredFile = myModule1Dir.createChildData(this, "CVS"); DirectoryInfo info = myIndex.getInfoForFile(ignoredFile); assertTrue(info.isIgnored()); - assertTrue(ProjectRootManager.getInstance(myProject).getFileIndex().isExcluded(ignoredFile)); + assertTrue(myFileIndex.isExcluded(ignoredFile)); + assertTrue(myFileIndex.isUnderIgnored(ignoredFile)); } public void testAddModule() throws Exception { @@ -386,10 +401,12 @@ public class DirectoryIndexTest extends IdeaTestCase { public void testModuleUnderIgnoredDir() throws IOException { final VirtualFile ignored = myRootVFile.createChildDirectory(this, "RCS"); assertTrue(FileTypeManager.getInstance().isFileIgnored(ignored)); - assertTrue(ProjectRootManager.getInstance(myProject).getFileIndex().isExcluded(ignored)); + assertTrue(myFileIndex.isExcluded(ignored)); + assertTrue(myFileIndex.isUnderIgnored(ignored)); final VirtualFile module4 = ignored.createChildDirectory(this, "module4"); assertFalse(FileTypeManager.getInstance().isFileIgnored(module4)); - assertTrue(ProjectRootManager.getInstance(myProject).getFileIndex().isExcluded(module4)); + assertTrue(myFileIndex.isExcluded(module4)); + assertTrue(myFileIndex.isUnderIgnored(module4)); new WriteCommandAction.Simple(getProject()) { @Override @@ -425,11 +442,12 @@ public class DirectoryIndexTest extends IdeaTestCase { } public void testExcludedDirsInLibraries() { - ProjectFileIndex index = ProjectRootManager.getInstance(myProject).getFileIndex(); - assertFalse(index.isInLibraryClasses(myExcludedLibClsDir)); - assertTrue(index.isExcluded(myExcludedLibClsDir)); - assertFalse(index.isInLibrarySource(myExcludedLibSrcDir)); - assertTrue(index.isExcluded(myExcludedLibSrcDir)); + assertFalse(myFileIndex.isInLibraryClasses(myExcludedLibClsDir)); + assertTrue(myFileIndex.isExcluded(myExcludedLibClsDir)); + assertFalse(myFileIndex.isUnderIgnored(myExcludedLibClsDir)); + assertFalse(myFileIndex.isInLibrarySource(myExcludedLibSrcDir)); + assertTrue(myFileIndex.isExcluded(myExcludedLibSrcDir)); + assertFalse(myFileIndex.isUnderIgnored(myExcludedLibSrcDir)); } public void testExplicitExcludeOfInner() throws Exception { @@ -469,12 +487,12 @@ public class DirectoryIndexTest extends IdeaTestCase { ModuleRootModificationUtil.addModuleLibrary(myModule, "someLib", Collections.<String>emptyList(), Arrays.asList(mySrcDir1.getUrl())); checkInfo(mySrcDir1, myModule, false, true, "", JavaSourceRootType.SOURCE, myModule, myModule); - OrderEntry[] entries = myIndex.getInfoForFile(mySrcDir1).getOrderEntries(); + OrderEntry[] entries = myIndex.getOrderEntries(myIndex.getInfoForFile(mySrcDir1)); assertInstanceOf(entries[0], LibraryOrderEntry.class); assertInstanceOf(entries[1], ModuleSourceOrderEntry.class); checkInfo(myTestSrc1, myModule, false, true, "testSrc", JavaSourceRootType.TEST_SOURCE, myModule, myModule); - entries = myIndex.getInfoForFile(myTestSrc1).getOrderEntries(); + entries = myIndex.getOrderEntries(myIndex.getInfoForFile(myTestSrc1)); assertInstanceOf(entries[0], LibraryOrderEntry.class); assertInstanceOf(entries[1], ModuleSourceOrderEntry.class); } @@ -482,7 +500,7 @@ public class DirectoryIndexTest extends IdeaTestCase { public void testModuleSourceAsLibraryClasses() throws Exception { ModuleRootModificationUtil.addModuleLibrary(myModule, "someLib", Arrays.asList(mySrcDir1.getUrl()), Collections.<String>emptyList()); checkInfo(mySrcDir1, myModule, true, false, "", JavaSourceRootType.SOURCE, myModule); - assertInstanceOf(assertOneElement(assertInProject(mySrcDir1).getOrderEntries()), ModuleSourceOrderEntry.class); + assertInstanceOf(assertOneElement(myIndex.getOrderEntries(assertInProject(mySrcDir1))), ModuleSourceOrderEntry.class); } public void testModulesWithSameSourceContentRoot() { @@ -645,7 +663,7 @@ public class DirectoryIndexTest extends IdeaTestCase { checkInfo(myLibSrcDir, myModule, true, true, "", null, myModule, myModule3); checkInfo(myResDir, myModule, true, false, "", JavaResourceRootType.RESOURCE, myModule); - assertInstanceOf(assertOneElement(assertInProject(myResDir).getOrderEntries()), ModuleSourceOrderEntry.class); + assertInstanceOf(assertOneElement(myIndex.getOrderEntries(assertInProject(myResDir))), ModuleSourceOrderEntry.class); checkInfo(myExcludedLibSrcDir, null, true, false, "lib.src.exc", null, myModule3, myModule); checkInfo(myExcludedLibClsDir, null, true, false, "lib.cls.exc", null, myModule3); @@ -661,10 +679,10 @@ public class DirectoryIndexTest extends IdeaTestCase { } public void testExcludeCompilerOutputOutsideOfContentRoot() throws Exception { - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - assertTrue(fileIndex.isExcluded(myOutputDir)); - assertTrue(fileIndex.isExcluded(myModule1OutputDir)); - assertFalse(fileIndex.isExcluded(myOutputDir.getParent())); + assertTrue(myFileIndex.isExcluded(myOutputDir)); + assertFalse(myFileIndex.isUnderIgnored(myOutputDir)); + assertTrue(myFileIndex.isExcluded(myModule1OutputDir)); + assertFalse(myFileIndex.isExcluded(myOutputDir.getParent())); assertExcludedFromProject(myOutputDir); assertExcludedFromProject(myModule1OutputDir); String moduleOutputUrl = myModule1OutputDir.getUrl(); @@ -677,7 +695,7 @@ public class DirectoryIndexTest extends IdeaTestCase { assertExcludedFromProject(myOutputDir); assertExcludedFromProject(myModule1OutputDir); - assertTrue(fileIndex.isExcluded(myModule1OutputDir)); + assertTrue(myFileIndex.isExcluded(myModule1OutputDir)); PsiTestUtil.setCompilerOutputPath(myModule, moduleOutputUrl, true); PsiTestUtil.setCompilerOutputPath(myModule2, moduleOutputUrl, false); @@ -703,49 +721,47 @@ public class DirectoryIndexTest extends IdeaTestCase { } public void testFileContentAndSourceRoots() throws IOException { - ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - VirtualFile fileRoot = myRootVFile.createChildData(this, "fileRoot.txt"); VirtualFile fileSourceRoot = myRootVFile.createChildData(this, "fileSourceRoot.txt"); VirtualFile fileTestSourceRoot = myRootVFile.createChildData(this, "fileTestSourceRoot.txt"); assertNotInProject(fileRoot); - assertFalse(fileIndex.isInContent(fileRoot)); - assertIteratedContent(fileIndex, null, Arrays.asList(fileRoot, fileSourceRoot, fileTestSourceRoot)); + assertFalse(myFileIndex.isInContent(fileRoot)); + assertIteratedContent(myFileIndex, null, Arrays.asList(fileRoot, fileSourceRoot, fileTestSourceRoot)); ContentEntry contentEntry = PsiTestUtil.addContentRoot(myModule, fileRoot); assertEquals(fileRoot, contentEntry.getFile()); checkInfo(fileRoot, myModule, false, false, "", null); - assertTrue(fileIndex.isInContent(fileRoot)); - assertFalse(fileIndex.isInSource(fileRoot)); + assertTrue(myFileIndex.isInContent(fileRoot)); + assertFalse(myFileIndex.isInSource(fileRoot)); PsiTestUtil.addContentRoot(myModule, fileSourceRoot); PsiTestUtil.addSourceRoot(myModule, fileSourceRoot); checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule); - assertTrue(fileIndex.isInContent(fileSourceRoot)); - assertTrue(fileIndex.isInSource(fileSourceRoot)); + assertTrue(myFileIndex.isInContent(fileSourceRoot)); + assertTrue(myFileIndex.isInSource(fileSourceRoot)); PsiTestUtil.addContentRoot(myModule, fileTestSourceRoot); PsiTestUtil.addSourceRoot(myModule, fileTestSourceRoot, true); checkInfo(fileTestSourceRoot, myModule, false, false, "", JavaSourceRootType.TEST_SOURCE, myModule); - assertTrue(fileIndex.isInContent(fileTestSourceRoot)); - assertTrue(fileIndex.isInSource(fileTestSourceRoot)); + assertTrue(myFileIndex.isInContent(fileTestSourceRoot)); + assertTrue(myFileIndex.isInSource(fileTestSourceRoot)); - assertIteratedContent(fileIndex, Arrays.asList(fileRoot, fileSourceRoot, fileTestSourceRoot), null); + assertIteratedContent(myFileIndex, Arrays.asList(fileRoot, fileSourceRoot, fileTestSourceRoot), null); // removing file source root PsiTestUtil.removeSourceRoot(myModule, fileTestSourceRoot); checkInfo(fileTestSourceRoot, myModule, false, false, "", null); - assertTrue(fileIndex.isInContent(fileTestSourceRoot)); - assertFalse(fileIndex.isInSource(fileTestSourceRoot)); - assertIteratedContent(fileIndex, Arrays.asList(fileRoot, fileSourceRoot, fileTestSourceRoot), null); + assertTrue(myFileIndex.isInContent(fileTestSourceRoot)); + assertFalse(myFileIndex.isInSource(fileTestSourceRoot)); + assertIteratedContent(myFileIndex, Arrays.asList(fileRoot, fileSourceRoot, fileTestSourceRoot), null); // removing file content root - PsiTestUtil.removeContentEntry(myModule, contentEntry); + PsiTestUtil.removeContentEntry(myModule, contentEntry.getFile()); assertNotInProject(fileRoot); - assertFalse(fileIndex.isInContent(fileRoot)); - assertFalse(fileIndex.isInSource(fileRoot)); - assertIteratedContent(fileIndex, Arrays.asList(fileSourceRoot, fileTestSourceRoot), Arrays.asList(fileRoot)); + assertFalse(myFileIndex.isInContent(fileRoot)); + assertFalse(myFileIndex.isInSource(fileRoot)); + assertIteratedContent(myFileIndex, Arrays.asList(fileSourceRoot, fileTestSourceRoot), Arrays.asList(fileRoot)); } private void assertIteratedContent(ProjectFileIndex fileIndex, @@ -764,63 +780,57 @@ public class DirectoryIndexTest extends IdeaTestCase { } public void testFileSourceRootsUnderDirContentRoot() throws IOException { - ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - VirtualFile fileSourceRoot = myModule1Dir.createChildData(this, "fileSourceRoot.txt"); - assertTrue(fileIndex.isInContent(fileSourceRoot)); - assertFalse(fileIndex.isInSource(fileSourceRoot)); + assertTrue(myFileIndex.isInContent(fileSourceRoot)); + assertFalse(myFileIndex.isInSource(fileSourceRoot)); PsiTestUtil.addSourceRoot(myModule, fileSourceRoot); - assertTrue(fileIndex.isInContent(fileSourceRoot)); - assertTrue(fileIndex.isInSource(fileSourceRoot)); + assertTrue(myFileIndex.isInContent(fileSourceRoot)); + assertTrue(myFileIndex.isInSource(fileSourceRoot)); checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule); // removing file source root PsiTestUtil.removeSourceRoot(myModule, fileSourceRoot); - assertTrue(fileIndex.isInContent(fileSourceRoot)); - assertFalse(fileIndex.isInSource(fileSourceRoot)); + assertTrue(myFileIndex.isInContent(fileSourceRoot)); + assertFalse(myFileIndex.isInSource(fileSourceRoot)); } public void testFileModuleExcludeRootUnderDirectoryRoot() throws IOException { - ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - VirtualFile fileExcludeRoot = mySrcDir1.createChildData(this, "fileExcludeRoot.txt"); - assertTrue(fileIndex.isInContent(fileExcludeRoot)); - assertTrue(fileIndex.isInSource(fileExcludeRoot)); - assertIteratedContent(fileIndex, Arrays.asList(fileExcludeRoot), null); + assertTrue(myFileIndex.isInContent(fileExcludeRoot)); + assertTrue(myFileIndex.isInSource(fileExcludeRoot)); + assertIteratedContent(myFileIndex, Arrays.asList(fileExcludeRoot), null); PsiTestUtil.addExcludedRoot(myModule, fileExcludeRoot); - assertFalse(fileIndex.isInContent(fileExcludeRoot)); - assertFalse(fileIndex.isInSource(fileExcludeRoot)); + assertFalse(myFileIndex.isInContent(fileExcludeRoot)); + assertFalse(myFileIndex.isInSource(fileExcludeRoot)); assertExcluded(fileExcludeRoot, myModule); - assertIteratedContent(fileIndex, null, Arrays.asList(fileExcludeRoot)); + assertIteratedContent(myFileIndex, null, Arrays.asList(fileExcludeRoot)); // removing file exclude root PsiTestUtil.removeExcludedRoot(myModule, fileExcludeRoot); - assertTrue(fileIndex.isInContent(fileExcludeRoot)); - assertTrue(fileIndex.isInSource(fileExcludeRoot)); - assertIteratedContent(fileIndex, Arrays.asList(fileExcludeRoot), null); + assertTrue(myFileIndex.isInContent(fileExcludeRoot)); + assertTrue(myFileIndex.isInSource(fileExcludeRoot)); + assertIteratedContent(myFileIndex, Arrays.asList(fileExcludeRoot), null); } public void testFileModuleExcludeRootUnderFileRoot() throws IOException { - ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - VirtualFile fileRoot = myRootVFile.createChildData(this, "fileRoot.txt"); PsiTestUtil.addContentRoot(myModule, fileRoot); checkInfo(fileRoot, myModule, false, false, "", null); - assertTrue(fileIndex.isInContent(fileRoot)); - assertIteratedContent(fileIndex, Arrays.asList(fileRoot), null); + assertTrue(myFileIndex.isInContent(fileRoot)); + assertIteratedContent(myFileIndex, Arrays.asList(fileRoot), null); PsiTestUtil.addExcludedRoot(myModule, fileRoot); - assertFalse(fileIndex.isInContent(fileRoot)); + assertFalse(myFileIndex.isInContent(fileRoot)); assertExcluded(fileRoot, myModule); - assertIteratedContent(fileIndex, null, Arrays.asList(fileRoot)); + assertIteratedContent(myFileIndex, null, Arrays.asList(fileRoot)); // removing file exclude root PsiTestUtil.removeExcludedRoot(myModule, fileRoot); checkInfo(fileRoot, myModule, false, false, "", null); - assertTrue(fileIndex.isInContent(fileRoot)); - assertIteratedContent(fileIndex, Arrays.asList(fileRoot), null); + assertTrue(myFileIndex.isInContent(fileRoot)); + assertIteratedContent(myFileIndex, Arrays.asList(fileRoot), null); } public void testFileLibraryInsideFolderLibrary() throws IOException { @@ -835,8 +845,6 @@ public class DirectoryIndexTest extends IdeaTestCase { } public void testFileContentRootsModifications() throws IOException { - ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - VirtualFile temp = myRootVFile.createChildDirectory(this, "temp"); VirtualFile fileSourceRoot = myRootVFile.createChildData(this, "fileSourceRoot.txt"); @@ -845,54 +853,54 @@ public class DirectoryIndexTest extends IdeaTestCase { PsiTestUtil.addContentRoot(myModule, fileSourceRoot); PsiTestUtil.addSourceRoot(myModule, fileSourceRoot); checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule); - assertTrue(fileIndex.isInContent(fileSourceRoot)); - assertTrue(fileIndex.isInSource(fileSourceRoot)); + assertTrue(myFileIndex.isInContent(fileSourceRoot)); + assertTrue(myFileIndex.isInSource(fileSourceRoot)); // delete and recreate fileSourceRoot.delete(this); assertNotInProject(fileSourceRoot); - assertFalse(fileIndex.isInContent(fileSourceRoot)); - assertFalse(fileIndex.isInSource(fileSourceRoot)); + assertFalse(myFileIndex.isInContent(fileSourceRoot)); + assertFalse(myFileIndex.isInSource(fileSourceRoot)); fileSourceRoot = myRootVFile.createChildData(this, "fileSourceRoot.txt"); checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule); - assertTrue(fileIndex.isInContent(fileSourceRoot)); - assertTrue(fileIndex.isInSource(fileSourceRoot)); + assertTrue(myFileIndex.isInContent(fileSourceRoot)); + assertTrue(myFileIndex.isInSource(fileSourceRoot)); // delete and move from another dir fileSourceRoot.delete(this); assertNotInProject(fileSourceRoot); - assertFalse(fileIndex.isInContent(fileSourceRoot)); - assertFalse(fileIndex.isInSource(fileSourceRoot)); + assertFalse(myFileIndex.isInContent(fileSourceRoot)); + assertFalse(myFileIndex.isInSource(fileSourceRoot)); fileSourceRoot = temp.createChildData(this, "fileSourceRoot.txt"); assertNotInProject(fileSourceRoot); fileSourceRoot.move(this, myRootVFile); checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule); - assertTrue(fileIndex.isInContent(fileSourceRoot)); - assertTrue(fileIndex.isInSource(fileSourceRoot)); + assertTrue(myFileIndex.isInContent(fileSourceRoot)); + assertTrue(myFileIndex.isInSource(fileSourceRoot)); // delete and copy from another dir fileSourceRoot.delete(this); assertNotInProject(fileSourceRoot); - assertFalse(fileIndex.isInContent(fileSourceRoot)); - assertFalse(fileIndex.isInSource(fileSourceRoot)); + assertFalse(myFileIndex.isInContent(fileSourceRoot)); + assertFalse(myFileIndex.isInSource(fileSourceRoot)); fileSourceRoot = temp.createChildData(this, "fileSourceRoot.txt"); assertNotInProject(fileSourceRoot); fileSourceRoot = fileSourceRoot.copy(this, myRootVFile, "fileSourceRoot.txt"); checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule); - assertTrue(fileIndex.isInContent(fileSourceRoot)); - assertTrue(fileIndex.isInSource(fileSourceRoot)); + assertTrue(myFileIndex.isInContent(fileSourceRoot)); + assertTrue(myFileIndex.isInSource(fileSourceRoot)); // delete and rename from another file fileSourceRoot.delete(this); assertNotInProject(fileSourceRoot); - assertFalse(fileIndex.isInContent(fileSourceRoot)); - assertFalse(fileIndex.isInSource(fileSourceRoot)); + assertFalse(myFileIndex.isInContent(fileSourceRoot)); + assertFalse(myFileIndex.isInSource(fileSourceRoot)); fileSourceRoot = myRootVFile.createChildData(this, "temp_file.txt"); assertNotInProject(fileSourceRoot); fileSourceRoot.rename(this, "fileSourceRoot.txt"); checkInfo(fileSourceRoot, myModule, false, false, "", JavaSourceRootType.SOURCE, myModule); - assertTrue(fileIndex.isInContent(fileSourceRoot)); - assertTrue(fileIndex.isInSource(fileSourceRoot)); + assertTrue(myFileIndex.isInContent(fileSourceRoot)); + assertTrue(myFileIndex.isInSource(fileSourceRoot)); } private void checkInfo(VirtualFile file, @@ -914,15 +922,14 @@ public class DirectoryIndexTest extends IdeaTestCase { assertEquals(isInLibrary, info.hasLibraryClassRoot()); assertEquals(isInLibrarySource, info.isInLibrarySource()); - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); if (file.isDirectory()) { - assertEquals(packageName, fileIndex.getPackageNameByDirectory(file)); + assertEquals(packageName, myFileIndex.getPackageNameByDirectory(file)); } - assertEquals(Arrays.toString(info.getOrderEntries()), modulesOfOrderEntries.length, info.getOrderEntries().length); + assertEquals(Arrays.toString(myIndex.getOrderEntries(info)), modulesOfOrderEntries.length, myIndex.getOrderEntries(info).length); for (Module aModule : modulesOfOrderEntries) { - OrderEntry found = info.findOrderEntryWithOwnerModule(aModule); - assertNotNull("not found: " + aModule + " in " + Arrays.toString(info.getOrderEntries()), found); + OrderEntry found = myIndex.findOrderEntryWithOwnerModule(info, aModule); + assertNotNull("not found: " + aModule + " in " + Arrays.toString(myIndex.getOrderEntries(info)), found); } } @@ -941,7 +948,7 @@ public class DirectoryIndexTest extends IdeaTestCase { private DirectoryInfo assertInProject(VirtualFile file) { DirectoryInfo info = myIndex.getInfoForFile(file); assertTrue(file.toString(), info.isInProject()); - info.assertConsistency(); + myIndex.assertConsistency(info); return info; } @@ -957,6 +964,11 @@ public class DirectoryIndexTest extends IdeaTestCase { VirtualFile[] actualDirs = myIndex.getDirectoriesByPackageName(packageName, includeLibrarySources).toArray(VirtualFile.EMPTY_ARRAY); assertNotNull(actualDirs); assertOrderedEquals(actualDirs, expectedDirs); + + for (VirtualFile dir : expectedDirs) { + String actualName = myIndex.getPackageName(dir); + assertEquals("Invalid package name for dir " + dir + ": " + packageName, packageName, actualName); + } } } diff --git a/java/java-tests/testSrc/com/intellij/psi/MiscPsiTest.java b/java/java-tests/testSrc/com/intellij/psi/MiscPsiTest.java index 096547c4f4db..61414ab0b416 100644 --- a/java/java-tests/testSrc/com/intellij/psi/MiscPsiTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/MiscPsiTest.java @@ -260,4 +260,20 @@ public class MiscPsiTest extends LightCodeInsightFixtureTestCase { assertEquals("some.unknown.Foo<? extends String>", type.getCanonicalText()); } + public void testNoPsiModificationsInUncommittedDocument() { + final PsiJavaFile file = (PsiJavaFile)myFixture.addFileToProject("a.java", "class A{}"); + Document document = file.getViewProvider().getDocument(); + document.insertString(0, " "); + + PsiClass psiClass = file.getClasses()[0]; + try { + psiClass.addBefore(PsiParserFacade.SERVICE.getInstance(getProject()).createWhiteSpaceFromText(" "), psiClass.getLBrace()); + fail(); + } + catch (IllegalStateException e) { + assertEquals("Attempt to modify PSI for non-committed Document!", e.getMessage()); + } + assertEquals("class A{}", psiClass.getText()); + assertEquals(" class A{}", document.getText()); + } } diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerFieldReferenceTest.groovy b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerFieldReferenceTest.groovy index d11a34f6e376..7b1861b9daec 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerFieldReferenceTest.groovy +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerFieldReferenceTest.groovy @@ -385,4 +385,28 @@ public class test { ] ) } + + void "test IDEA-128071"() { + doTest( + initial: ''' +public class FormatTest { + public int a = 3; + private static final String FACEBOOK_CLIENT_ID = ""; + public static final String FACEBOOK_OAUTH_URL = "".concat(FACEBOOK_CLIENT_ID).concat(""); +} +''', + expected: ''' +public class FormatTest { + private static final String FACEBOOK_CLIENT_ID = ""; + public static final String FACEBOOK_OAUTH_URL = "".concat(FACEBOOK_CLIENT_ID).concat(""); + public int a = 3; +} +''', + rules: [ + rule(PUBLIC, STATIC, FINAL), + rule(PRIVATE, STATIC, FINAL), + rule(PUBLIC) + ] + ) + } } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java b/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java index 204525cb6822..e830594db39f 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java @@ -208,6 +208,10 @@ public class RenameCollisionsTest extends LightRefactoringTestCase { doTest("foo2"); } + public void testRenameMethodNoCollisionWithOtherSignatureMethodRef() throws Exception { + doTest("foo2"); + } + public void testRenameNoStaticOverridingInInterfaces() throws Exception { doTest("foo"); } diff --git a/java/java-tests/testSrc/com/intellij/roots/ModuleScopesTest.java b/java/java-tests/testSrc/com/intellij/roots/ModuleScopesTest.java index 514348e5913b..0ad26a34eec5 100644 --- a/java/java-tests/testSrc/com/intellij/roots/ModuleScopesTest.java +++ b/java/java-tests/testSrc/com/intellij/roots/ModuleScopesTest.java @@ -105,15 +105,21 @@ public class ModuleScopesTest extends ModuleTestCase { } private Module addDependentModule(final Module moduleA, final DependencyScope scope) { - final Module moduleB = createModule("b.iml", StdModuleTypes.JAVA); + return addDependentModule("b", moduleA, scope, false); + } + + private Module addDependentModule(final String name, final Module moduleA, + final DependencyScope scope, + final boolean exported) { + final Module moduleB = createModule(name + ".iml", StdModuleTypes.JAVA); ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - VirtualFile rootB = myFixture.findOrCreateDir("b"); + VirtualFile rootB = myFixture.findOrCreateDir(name); VirtualFile outB = myFixture.findOrCreateDir("out"); - ModuleRootModificationUtil.addDependency(moduleA, moduleB, scope, false); + ModuleRootModificationUtil.addDependency(moduleA, moduleB, scope, exported); PsiTestUtil.addSourceRoot(moduleB, rootB); PsiTestUtil.setCompilerOutputPath(moduleB, outB.getUrl(), false); @@ -123,6 +129,25 @@ public class ModuleScopesTest extends ModuleTestCase { return moduleB; } + public void testModuleTwiceInDependents() throws IOException { + Module m = createModule("m.iml", StdModuleTypes.JAVA); + Module a = createModule("a.iml", StdModuleTypes.JAVA); + Module b = createModule("b.iml", StdModuleTypes.JAVA); + Module c = createModule("c.iml", StdModuleTypes.JAVA); + + ModuleRootModificationUtil.addDependency(a, m, DependencyScope.COMPILE, false); + ModuleRootModificationUtil.addDependency(b, m, DependencyScope.COMPILE, true); + ModuleRootModificationUtil.addDependency(a, b, DependencyScope.COMPILE, true); + ModuleRootModificationUtil.addDependency(c, a, DependencyScope.COMPILE, true); + + VirtualFile root = myFixture.findOrCreateDir("c"); + PsiTestUtil.addSourceContentToRoots(c, root); + VirtualFile file = root.createChildData(this, "x.txt"); + + GlobalSearchScope deps = m.getModuleWithDependentsScope(); + assertTrue(deps.contains(file)); + } + public void testTestOnlyLibraryDependency() throws IOException { Module m = createModule("a.iml", StdModuleTypes.JAVA); addLibrary(m, DependencyScope.TEST); diff --git a/java/java-tests/testSrc/com/intellij/slicer/SliceTreeTest.java b/java/java-tests/testSrc/com/intellij/slicer/SliceTreeTest.java index 6e34ebf5f939..b6d8840059ba 100644 --- a/java/java-tests/testSrc/com/intellij/slicer/SliceTreeTest.java +++ b/java/java-tests/testSrc/com/intellij/slicer/SliceTreeTest.java @@ -49,7 +49,8 @@ public class SliceTreeTest extends SliceTestCase { SliceUsage usage = SliceUsage.createRootUsage(element, params); - SlicePanel panel = new SlicePanel(getProject(), true, new SliceRootNode(getProject(), new DuplicateMap(), usage), false, ToolWindowHeadlessManagerImpl.HEADLESS_WINDOW) { + ToolWindowHeadlessManagerImpl.MockToolWindow toolWindow = new ToolWindowHeadlessManagerImpl.MockToolWindow(myProject); + SlicePanel panel = new SlicePanel(getProject(), true, new SliceRootNode(getProject(), new DuplicateMap(), usage), false, toolWindow) { @Override protected void close() { } diff --git a/java/jsp-openapi/src/com/intellij/psi/jsp/JavaJspElementVisitor.java b/java/jsp-openapi/src/com/intellij/psi/jsp/JavaJspElementVisitor.java index 6eda197118bd..6100c98323bc 100644 --- a/java/jsp-openapi/src/com/intellij/psi/jsp/JavaJspElementVisitor.java +++ b/java/jsp-openapi/src/com/intellij/psi/jsp/JavaJspElementVisitor.java @@ -21,9 +21,6 @@ import com.intellij.psi.JavaElementVisitor; * @author yole */ public abstract class JavaJspElementVisitor extends JavaElementVisitor { - public void visitJspImplicitVariable(JspImplicitVariable variable){ - visitImplicitVariable(variable); - } public void visitJspFile(JspFile jspFile) { visitFile(jspFile); diff --git a/java/openapi/src/com/intellij/ui/classFilter/ClassFilter.java b/java/openapi/src/com/intellij/ui/classFilter/ClassFilter.java index 05500e31ebd3..b93deafa1fe8 100644 --- a/java/openapi/src/com/intellij/ui/classFilter/ClassFilter.java +++ b/java/openapi/src/com/intellij/ui/classFilter/ClassFilter.java @@ -17,15 +17,20 @@ package com.intellij.ui.classFilter; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.DefaultJDOMExternalizer; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.JDOMExternalizable; +import com.intellij.openapi.util.WriteExternalException; import com.intellij.util.xmlb.annotations.Attribute; import com.intellij.util.xmlb.annotations.Tag; import com.intellij.util.xmlb.annotations.Transient; +import org.jdom.Element; import java.util.regex.Matcher; import java.util.regex.Pattern; @Tag("class-filter") -public class ClassFilter implements Cloneable { +public class ClassFilter implements JDOMExternalizable, Cloneable{ private static final Logger LOG = Logger.getInstance("#com.intellij.ui.classFilter.ClassFilter"); public static final ClassFilter[] EMPTY_ARRAY = new ClassFilter[0]; @@ -67,6 +72,16 @@ public class ClassFilter implements Cloneable { return getPattern(); } + @Override + public void readExternal(Element element) throws InvalidDataException { + DefaultJDOMExternalizer.readExternal(this, element); + } + + @Override + public void writeExternal(Element element) throws WriteExternalException { + DefaultJDOMExternalizer.writeExternal(this, element); + } + public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ClassFilter)) return false; diff --git a/java/remote-servers/impl/remote-servers-java-impl.iml b/java/remote-servers/impl/remote-servers-java-impl.iml index 6999e2deac71..15781473aa45 100644 --- a/java/remote-servers/impl/remote-servers-java-impl.iml +++ b/java/remote-servers/impl/remote-servers-java-impl.iml @@ -15,6 +15,7 @@ <orderEntry type="module" module-name="remote-servers-impl" /> <orderEntry type="module" module-name="java-impl" /> <orderEntry type="module" module-name="openapi" /> + <orderEntry type="module" module-name="idea-ui" /> </component> </module> diff --git a/java/remote-servers/impl/src/META-INF/RemoteServersJava.xml b/java/remote-servers/impl/src/META-INF/RemoteServersJava.xml index 24a0776ccd29..692199e3bb2c 100644 --- a/java/remote-servers/impl/src/META-INF/RemoteServersJava.xml +++ b/java/remote-servers/impl/src/META-INF/RemoteServersJava.xml @@ -2,7 +2,7 @@ <extensionPoints> <extensionPoint qualifiedName="com.intellij.remoteServer.moduleBuilderContribution" - interface="com.intellij.remoteServer.impl.module.CloudModuleBuilderContribution"/> + interface="com.intellij.remoteServer.impl.module.CloudModuleBuilderContributionFactory"/> </extensionPoints> <extensions defaultExtensionNs="com.intellij"> diff --git a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudApplicationConfigurable.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudApplicationConfigurable.java index 14bd043a7f23..e235eeeb55aa 100644 --- a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudApplicationConfigurable.java +++ b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudApplicationConfigurable.java @@ -15,152 +15,20 @@ */ package com.intellij.remoteServer.impl.module; -import com.intellij.openapi.Disposable; import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; import com.intellij.remoteServer.configuration.RemoteServer; -import com.intellij.remoteServer.runtime.Deployment; -import com.intellij.remoteServer.runtime.ServerConnection; -import com.intellij.remoteServer.runtime.ServerConnector; -import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance; -import com.intellij.remoteServer.util.*; -import com.intellij.util.concurrency.Semaphore; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import java.util.Collection; -import java.util.concurrent.atomic.AtomicReference; +import java.awt.*; -public abstract class CloudApplicationConfigurable< - SC extends CloudConfigurationBase, - DC extends CloudDeploymentNameConfiguration, - SR extends CloudMultiSourceServerRuntimeInstance<DC, ?, ?, ?>, - AC extends CloudApplicationConfiguration> { +public abstract class CloudApplicationConfigurable { - private final Project myProject; - private final Disposable myParentDisposable; + public abstract Component getComponent(); - private DelayedRunner myRunner; + public abstract void setAccount(RemoteServer<?> account); - private RemoteServer<?> myAccount; - - public CloudApplicationConfigurable(@Nullable Project project, Disposable parentDisposable) { - myProject = project; - myParentDisposable = parentDisposable; - } - - public void setAccount(RemoteServer<?> account) { - myAccount = account; - clearCloudData(); - } - - protected RemoteServer<SC> getAccount() { - return (RemoteServer<SC>)myAccount; - } - - public JComponent getComponent() { - JComponent result = getMainPanel(); - if (myRunner == null) { - myRunner = new DelayedRunner(result) { - - private RemoteServer<?> myPreviousAccount; - - @Override - protected boolean wasChanged() { - boolean result = myPreviousAccount != myAccount; - if (result) { - myPreviousAccount = myAccount; - } - return result; - } - - @Override - protected void run() { - loadCloudData(); - } - }; - Disposer.register(myParentDisposable, myRunner); - } - return result; - } - - protected void clearCloudData() { - getExistingComboBox().removeAllItems(); - } - - protected void loadCloudData() { - new ConnectionTask<Collection<Deployment>>("Loading existing applications list") { - - @Override - protected void run(final ServerConnection<DC> connection, - final Semaphore semaphore, - final AtomicReference<Collection<Deployment>> result) { - connection.connectIfNeeded(new ServerConnector.ConnectionCallback<DC>() { - - @Override - public void connected(@NotNull ServerRuntimeInstance<DC> serverRuntimeInstance) { - connection.computeDeployments(new Runnable() { - - @Override - public void run() { - result.set(connection.getDeployments()); - semaphore.up(); - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - if (!Disposer.isDisposed(myParentDisposable)) { - setupExistingApplications(result.get()); - } - } - }); - } - }); - } - - @Override - public void errorOccurred(@NotNull String errorMessage) { - runtimeErrorOccurred(errorMessage); - semaphore.up(); - } - }); - } - - @Override - protected Collection<Deployment> run(SR serverRuntimeInstance) throws ServerRuntimeException { - return null; - } - }.performAsync(); - } - - private void setupExistingApplications(Collection<Deployment> deployments) { - JComboBox existingComboBox = getExistingComboBox(); - existingComboBox.removeAllItems(); - for (Deployment deployment : deployments) { - existingComboBox.addItem(deployment.getName()); - } - } - - protected Project getProject() { - return myProject; - } - - protected abstract JComboBox getExistingComboBox(); - - protected abstract JComponent getMainPanel(); - - public abstract AC createConfiguration(); + public abstract CloudApplicationConfiguration createConfiguration(); public abstract void validate() throws ConfigurationException; - - protected abstract class ConnectionTask<T> extends CloudConnectionTask<T, SC, DC, SR> { - - public ConnectionTask(String title) { - super(myProject, title, CloudApplicationConfigurable.this.getAccount()); - } - } } diff --git a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudApplicationConfiguration.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudApplicationConfiguration.java index 9af0f1ad472b..af9fa723e82a 100644 --- a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudApplicationConfiguration.java +++ b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudApplicationConfiguration.java @@ -18,19 +18,4 @@ package com.intellij.remoteServer.impl.module; public abstract class CloudApplicationConfiguration { - private boolean myExisting; - private final String myExistingAppName; - - protected CloudApplicationConfiguration(boolean existing, String existingAppName) { - myExisting = existing; - myExistingAppName = existingAppName; - } - - public boolean isExisting() { - return myExisting; - } - - public String getExistingAppName() { - return myExistingAppName; - } } diff --git a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilder.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilder.java index 4aa8d60bcea4..62e256c14c8e 100644 --- a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilder.java +++ b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilder.java @@ -16,6 +16,7 @@ package com.intellij.remoteServer.impl.module; import com.intellij.icons.AllIcons; +import com.intellij.ide.util.newProjectWizard.impl.FrameworkSupportModelBase; import com.intellij.ide.util.projectWizard.JavaModuleBuilder; import com.intellij.ide.util.projectWizard.ModuleBuilderListener; import com.intellij.ide.util.projectWizard.ModuleWizardStep; @@ -23,20 +24,42 @@ import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.openapi.Disposable; import com.intellij.openapi.module.JavaModuleType; import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ui.configuration.ModulesProvider; +import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer; +import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainerFactory; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.remoteServer.ServerType; import com.intellij.remoteServer.configuration.RemoteServer; +import com.intellij.util.containers.hash.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.Map; public class CloudModuleBuilder extends JavaModuleBuilder { private RemoteServer<?> myAccount; private CloudApplicationConfiguration myApplicationConfiguration; + private FrameworkSupportModelBase myFrameworkSupportModel; + + private Map<ServerType<?>, CloudModuleBuilderContribution> myCloudType2Contribution; + private Project myProject; public CloudModuleBuilder() { + myCloudType2Contribution = new HashMap<ServerType<?>, CloudModuleBuilderContribution>(); + + ModuleConfigurationUpdater configurationUpdater = new ModuleConfigurationUpdater() { + + public void update(@NotNull final Module module, @NotNull final ModifiableRootModel rootModel) { + preConfigureModule(module, rootModel); + } + }; + addModuleConfigurationUpdater(configurationUpdater); + addListener(new ModuleBuilderListener() { @Override @@ -93,7 +116,8 @@ public class CloudModuleBuilder extends JavaModuleBuilder { @Nullable @Override public ModuleWizardStep getCustomOptionsStep(WizardContext context, Disposable parentDisposable) { - return new CloudModuleWizardStep(this, context.getProject(), parentDisposable); + myProject = context.getProject(); + return new CloudModuleWizardStep(this, myProject, parentDisposable); } public void setAccount(RemoteServer<?> account) { @@ -108,7 +132,43 @@ public class CloudModuleBuilder extends JavaModuleBuilder { myApplicationConfiguration = applicationConfiguration; } + public CloudApplicationConfiguration getApplicationConfiguration() { + return myApplicationConfiguration; + } + + public CloudModuleBuilderContribution getContribution(ServerType<?> cloudType) { + CloudModuleBuilderContribution result = myCloudType2Contribution.get(cloudType); + if (result == null) { + result = CloudModuleBuilderContributionFactory.getInstanceByType(cloudType).createContribution(this); + myCloudType2Contribution.put(cloudType, result); + } + return result; + } + + private CloudModuleBuilderContribution getContribution() { + return getContribution(myAccount.getType()); + } + + private void preConfigureModule(Module module, ModifiableRootModel model) { + getContribution().preConfigureModule(module, model); + } + private void configureModule(final Module module) { - CloudModuleBuilderContribution.getInstanceByType(myAccount.getType()).configureModule(module, myAccount, myApplicationConfiguration); + getContribution().configureModule(module); + } + + public FrameworkSupportModelBase getFrameworkSupportModel() { + if (myFrameworkSupportModel == null) { + final LibrariesContainer librariesContainer = LibrariesContainerFactory.createContainer(myProject); + myFrameworkSupportModel = new FrameworkSupportModelBase(myProject, this, librariesContainer) { + + @NotNull + @Override + public String getBaseDirectoryForLibrariesPath() { + return StringUtil.notNullize(getContentEntryPath()); + } + }; + } + return myFrameworkSupportModel; } } diff --git a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContribution.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContribution.java index 6643c89cc1c4..dd2d9d9af563 100644 --- a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContribution.java +++ b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContribution.java @@ -16,33 +16,51 @@ package com.intellij.remoteServer.impl.module; import com.intellij.openapi.Disposable; -import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.remoteServer.ServerType; -import com.intellij.remoteServer.configuration.RemoteServer; +import com.intellij.remoteServer.configuration.deployment.DeploymentConfiguration; +import com.intellij.remoteServer.configuration.deployment.DeploymentSource; import org.jetbrains.annotations.Nullable; public abstract class CloudModuleBuilderContribution { - public static final ExtensionPointName<CloudModuleBuilderContribution> EP_NAME - = ExtensionPointName.create("com.intellij.remoteServer.moduleBuilderContribution"); + private final CloudModuleBuilder myModuleBuilder; - public abstract ServerType<?> getCloudType(); + private final ServerType<?> myCloudType; + private CloudApplicationConfigurable myApplicationConfigurable; - public abstract CloudApplicationConfigurable createApplicationConfigurable(@Nullable Project project, Disposable parentDisposable); + public CloudModuleBuilderContribution(CloudModuleBuilder moduleBuilder, ServerType<?> cloudType) { + myModuleBuilder = moduleBuilder; + myCloudType = cloudType; + } + + protected CloudModuleBuilder getModuleBuilder() { + return myModuleBuilder; + } - public abstract void configureModule(Module module, - RemoteServer<?> account, - CloudApplicationConfiguration configuration); + protected ServerType<?> getCloudType() { + return myCloudType; + } - public static CloudModuleBuilderContribution getInstanceByType(ServerType<?> cloudType) { - for (CloudModuleBuilderContribution contribution : EP_NAME.getExtensions()) { - if (contribution.getCloudType() == cloudType) { - return contribution; - } + public CloudApplicationConfigurable getApplicationConfigurable(@Nullable Project project, Disposable parentDisposable) { + if (myApplicationConfigurable == null) { + myApplicationConfigurable = createApplicationConfigurable(project, parentDisposable); } - return null; + return myApplicationConfigurable; + } + + public void preConfigureModule(Module module, ModifiableRootModel model) { + + } + + public abstract void configureModule(Module module); + + protected abstract CloudApplicationConfigurable createApplicationConfigurable(@Nullable Project project, Disposable parentDisposable); + + protected DeploymentConfiguration createDeploymentConfiguration(DeploymentSource deploymentSource) { + return myCloudType.createDeploymentConfigurator(null).createDefaultConfiguration(deploymentSource); } } diff --git a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContributionBase.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContributionBase.java deleted file mode 100644 index 6a927d97bb93..000000000000 --- a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContributionBase.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2000-2014 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.remoteServer.impl.module; - -import com.intellij.execution.RunManagerEx; -import com.intellij.execution.RunnerAndConfigurationSettings; -import com.intellij.execution.configurations.ConfigurationType; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModulePointer; -import com.intellij.openapi.module.ModulePointerManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.MessageType; -import com.intellij.remoteServer.ServerType; -import com.intellij.remoteServer.configuration.RemoteServer; -import com.intellij.remoteServer.impl.configuration.deployment.DeployToServerConfigurationType; -import com.intellij.remoteServer.impl.configuration.deployment.DeployToServerRunConfiguration; -import com.intellij.remoteServer.impl.configuration.deployment.ModuleDeploymentSourceImpl; -import com.intellij.remoteServer.util.*; -import com.intellij.remoteServer.util.ssh.SshKeyChecker; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - - -public abstract class CloudModuleBuilderContributionBase< - SC extends CloudConfigurationBase, - DC extends CloudDeploymentNameConfiguration, - AC extends CloudApplicationConfiguration, - SR extends CloudMultiSourceServerRuntimeInstance<DC, ?, ?, ?>> - extends CloudModuleBuilderContribution { - - @Override - public void configureModule(Module module, - RemoteServer<?> account, - CloudApplicationConfiguration applicationConfiguration) { - RemoteServer<SC> castedAccount = (RemoteServer<SC>)account; - final AC castedApplicationConfiguration = (AC)applicationConfiguration; - - DC deploymentConfiguration = createDeploymentConfiguration(); - - if (applicationConfiguration.isExisting()) { - deploymentConfiguration.setDefaultDeploymentName(false); - deploymentConfiguration.setDeploymentName(applicationConfiguration.getExistingAppName()); - } - - final DeployToServerRunConfiguration<SC, DC> runConfiguration = createRunConfiguration(module, castedAccount, deploymentConfiguration); - - final String cloudName = account.getType().getPresentableName(); - final Project project = module.getProject(); - new CloudConnectionTask<Object, SC, DC, SR>(project, CloudBundle.getText("cloud.support", cloudName), castedAccount) { - - CloudNotifier myNotifier = new CloudNotifier(cloudName); - - boolean myFirstAttempt = true; - - @Override - protected Object run(SR serverRuntime) throws ServerRuntimeException { - doConfigureModule(castedApplicationConfiguration, runConfiguration, myFirstAttempt, serverRuntime); - myNotifier.showMessage(CloudBundle.getText("cloud.support.added", cloudName), MessageType.INFO); - return null; - } - - @Override - protected void runtimeErrorOccurred(@NotNull String errorMessage) { - myFirstAttempt = false; - new SshKeyChecker().checkServerError(errorMessage, myNotifier, project, this); - } - }.performAsync(); - } - - private DeployToServerRunConfiguration<SC, DC> createRunConfiguration(Module module, - RemoteServer<SC> server, - DC deploymentConfiguration) { - Project project = module.getProject(); - - String serverName = server.getName(); - - String name = generateRunConfigurationName(serverName, module.getName()); - - final RunManagerEx runManager = RunManagerEx.getInstanceEx(project); - final RunnerAndConfigurationSettings runSettings - = runManager.createRunConfiguration(name, getRunConfigurationType().getConfigurationFactories()[0]); - - final DeployToServerRunConfiguration<SC, DC> result = (DeployToServerRunConfiguration<SC, DC>)runSettings.getConfiguration(); - - result.setServerName(serverName); - - final ModulePointer modulePointer = ModulePointerManager.getInstance(project).create(module); - result.setDeploymentSource(new ModuleDeploymentSourceImpl(modulePointer)); - - result.setDeploymentConfiguration(deploymentConfiguration); - - runManager.addConfiguration(runSettings, false); - runManager.setSelectedConfiguration(runSettings); - - return result; - } - - private static String generateRunConfigurationName(String serverName, String moduleName) { - return CloudBundle.getText("run.configuration.name", serverName, moduleName); - } - - private DeployToServerConfigurationType getRunConfigurationType() { - String id = DeployToServerConfigurationType.getId(getCloudType()); - for (ConfigurationType configurationType : ConfigurationType.CONFIGURATION_TYPE_EP.getExtensions()) { - if (configurationType instanceof DeployToServerConfigurationType) { - DeployToServerConfigurationType deployConfigurationType = (DeployToServerConfigurationType)configurationType; - if (deployConfigurationType.getId().equals(id)) { - return deployConfigurationType; - } - } - } - return null; - } - - @Override - public abstract ServerType<SC> getCloudType(); - - @Override - public abstract CloudApplicationConfigurable<SC, DC, SR, AC> createApplicationConfigurable(@Nullable Project project, - Disposable parentDisposable); - - protected abstract DC createDeploymentConfiguration(); - - protected abstract void doConfigureModule(AC applicationConfiguration, - DeployToServerRunConfiguration<SC, DC> runConfiguration, - boolean firstAttempt, - SR serverRuntime) throws ServerRuntimeException; -} diff --git a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContributionFactory.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContributionFactory.java new file mode 100644 index 000000000000..20ebc29fe148 --- /dev/null +++ b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContributionFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2014 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.remoteServer.impl.module; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.remoteServer.ServerType; + + +public abstract class CloudModuleBuilderContributionFactory { + + public static final ExtensionPointName<CloudModuleBuilderContributionFactory> EP_NAME + = ExtensionPointName.create("com.intellij.remoteServer.moduleBuilderContribution"); + + public abstract ServerType<?> getCloudType(); + + public abstract CloudModuleBuilderContribution createContribution(CloudModuleBuilder moduleBuilder); + + public static CloudModuleBuilderContributionFactory getInstanceByType(ServerType<?> cloudType) { + for (CloudModuleBuilderContributionFactory contribution : EP_NAME.getExtensions()) { + if (contribution.getCloudType() == cloudType) { + return contribution; + } + } + return null; + } +} diff --git a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderSourceContribution.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderSourceContribution.java new file mode 100644 index 000000000000..b5fdcc3995c8 --- /dev/null +++ b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderSourceContribution.java @@ -0,0 +1,191 @@ +/* + * Copyright 2000-2014 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.remoteServer.impl.module; + +import com.intellij.ide.util.newProjectWizard.StepSequence; +import com.intellij.ide.util.newProjectWizard.modes.CreateFromSourcesMode; +import com.intellij.ide.util.projectWizard.AbstractStepWithProgress; +import com.intellij.ide.util.projectWizard.ModuleWizardStep; +import com.intellij.ide.util.projectWizard.ProjectBuilder; +import com.intellij.ide.util.projectWizard.WizardContext; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ui.configuration.DefaultModulesProvider; +import com.intellij.openapi.roots.ui.configuration.ModulesProvider; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.util.Disposer; +import com.intellij.remoteServer.ServerType; +import com.intellij.remoteServer.configuration.RemoteServer; +import com.intellij.remoteServer.impl.configuration.deployment.DeployToServerRunConfiguration; +import com.intellij.remoteServer.util.*; +import com.intellij.remoteServer.util.ssh.SshKeyChecker; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + + +public abstract class CloudModuleBuilderSourceContribution< + SC extends CloudConfigurationBase, + DC extends CloudDeploymentNameConfiguration, + AC extends CloudSourceApplicationConfiguration, + SR extends CloudMultiSourceServerRuntimeInstance<DC, ?, ?, ?>> + extends CloudModuleBuilderContribution { + + private CloudNotifier myNotifier; + + public CloudModuleBuilderSourceContribution(CloudModuleBuilder moduleBuilder, ServerType<SC> cloudType) { + super(moduleBuilder, cloudType); + } + + @Override + public void configureModule(final Module module) { + final CloudModuleBuilder moduleBuilder = getModuleBuilder(); + RemoteServer<SC> account = (RemoteServer<SC>)moduleBuilder.getAccount(); + final AC applicationConfiguration = (AC)moduleBuilder.getApplicationConfiguration(); + + DC deploymentConfiguration = createDeploymentConfiguration(); + + if (applicationConfiguration.isExisting()) { + deploymentConfiguration.setDefaultDeploymentName(false); + deploymentConfiguration.setDeploymentName(applicationConfiguration.getExistingAppName()); + } + + final DeployToServerRunConfiguration<SC, DC> runConfiguration + = CloudRunConfigurationUtil.createRunConfiguration(account, module, deploymentConfiguration); + + final ServerType<?> cloudType = account.getType(); + final Project project = module.getProject(); + new CloudConnectionTask<Object, SC, DC, SR>(project, + CloudBundle.getText("cloud.support", cloudType.getPresentableName()), + account) { + + boolean myFirstAttempt = true; + + @Override + protected Object run(SR serverRuntime) throws ServerRuntimeException { + doConfigureModule(applicationConfiguration, runConfiguration, myFirstAttempt, serverRuntime); + return null; + } + + @Override + protected void runtimeErrorOccurred(@NotNull String errorMessage) { + myFirstAttempt = false; + new SshKeyChecker().checkServerError(errorMessage, getNotifier(), project, this); + } + + @Override + protected void postPerform(Object result) { + detectModuleStructure(module, moduleBuilder.getContentEntryPath()); + } + + @Override + protected boolean shouldStartInBackground() { + return false; + } + }.performAsync(); + } + + private CloudNotifier getNotifier() { + if (myNotifier == null) { + myNotifier = new CloudNotifier(getCloudType().getPresentableName()); + } + return myNotifier; + } + + private void detectModuleStructure(Module module, final String contentPath) { + final Project project = module.getProject(); + + final CreateFromSourcesMode mode = new CreateFromSourcesMode() { + + @Override + public boolean isAvailable(WizardContext context) { + return true; + } + + @Override + public void addSteps(WizardContext context, ModulesProvider modulesProvider, StepSequence sequence, String specific) { + super.addSteps(context, modulesProvider, sequence, specific); + myProjectBuilder.setFileToImport(contentPath); + } + }; + + final WizardContext context = new WizardContext(project); + + final StepSequence stepSequence = mode.getSteps(context, DefaultModulesProvider.createForProject(context.getProject())); + if (stepSequence == null) { + return; + } + + Disposer.register(project, new Disposable() { + + @Override + public void dispose() { + for (ModuleWizardStep step : stepSequence.getAllSteps()) { + step.disposeUIResources(); + } + } + }); + + ProgressManager.getInstance() + .run(new Task.Backgroundable(project, CloudBundle.getText("detect.module.structure", getCloudType().getPresentableName()), false) { + + @Override + public void run(@NotNull ProgressIndicator indicator) { + for (ModuleWizardStep step = ContainerUtil.getFirstItem(stepSequence.getSelectedSteps()); + step != null; + step = stepSequence.getNextStep(step)) { + if (step instanceof AbstractStepWithProgress<?>) { + ((AbstractStepWithProgress)step).performStep(); + } + else { + step.updateDataModel(); + } + } + CloudAccountSelectionEditor.unsetAccountOnContext(context, getCloudType()); + } + + @Override + public boolean shouldStartInBackground() { + return false; + } + + @Override + public void onSuccess() { + ProjectBuilder moduleBuilder = mode.getModuleBuilder(); + if (moduleBuilder == null) { + return; + } + moduleBuilder.commit(project); + getNotifier().showMessage(CloudBundle.getText("cloud.support.added", getCloudType().getPresentableName()), MessageType.INFO); + } + }); + } + + @Override + protected abstract CloudSourceApplicationConfigurable<SC, DC, SR, AC> createApplicationConfigurable(@Nullable Project project, + Disposable parentDisposable); + + protected abstract DC createDeploymentConfiguration(); + + protected abstract void doConfigureModule(AC applicationConfiguration, + DeployToServerRunConfiguration<SC, DC> runConfiguration, + boolean firstAttempt, + SR serverRuntime) throws ServerRuntimeException; +} diff --git a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleWizardStep.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleWizardStep.java index cf0e283616b2..79b307b0658e 100644 --- a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleWizardStep.java +++ b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleWizardStep.java @@ -22,13 +22,13 @@ import com.intellij.openapi.project.Project; import com.intellij.remoteServer.ServerType; import com.intellij.remoteServer.configuration.RemoteServer; import com.intellij.remoteServer.util.CloudAccountSelectionEditor; -import com.intellij.util.containers.hash.HashMap; +import com.intellij.util.containers.HashSet; import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.List; -import java.util.Map; +import java.util.Set; public class CloudModuleWizardStep extends ModuleWizardStep { @@ -43,17 +43,17 @@ public class CloudModuleWizardStep extends ModuleWizardStep { private CloudAccountSelectionEditor myAccountSelectionPanel; - private Map<ServerType<?>, CloudApplicationConfigurable> myCloudType2ApplicationConfigurable; + private Set<ServerType<?>> myApplicationConfigurableTypes; public CloudModuleWizardStep(CloudModuleBuilder moduleBuilder, Project project, Disposable parentDisposable) { myModuleBuilder = moduleBuilder; myProject = project; myParentDisposable = parentDisposable; - myCloudType2ApplicationConfigurable = new HashMap<ServerType<?>, CloudApplicationConfigurable>(); + myApplicationConfigurableTypes = new HashSet<ServerType<?>>(); List<ServerType<?>> cloudTypes = new ArrayList<ServerType<?>>(); - for (CloudModuleBuilderContribution contribution : CloudModuleBuilderContribution.EP_NAME.getExtensions()) { + for (CloudModuleBuilderContributionFactory contribution : CloudModuleBuilderContributionFactory.EP_NAME.getExtensions()) { cloudTypes.add(contribution.getCloudType()); } @@ -86,11 +86,8 @@ public class CloudModuleWizardStep extends ModuleWizardStep { ServerType<?> cloudType = account.getType(); String cardName = cloudType.getId(); - CloudApplicationConfigurable<?, ?, ?, ?> applicationConfigurable = getApplicationConfigurable(); - if (applicationConfigurable == null) { - applicationConfigurable - = CloudModuleBuilderContribution.getInstanceByType(cloudType).createApplicationConfigurable(myProject, myParentDisposable); - myCloudType2ApplicationConfigurable.put(cloudType, applicationConfigurable); + CloudApplicationConfigurable applicationConfigurable = getApplicationConfigurable(); + if (myApplicationConfigurableTypes.add(cloudType)) { myApplicationPanelPlaceHolder.add(applicationConfigurable.getComponent(), cardName); } applicationPlaceHolderLayout.show(myApplicationPanelPlaceHolder, cardName); @@ -103,25 +100,25 @@ public class CloudModuleWizardStep extends ModuleWizardStep { return myMainPanel; } - private CloudApplicationConfigurable<?, ?, ?, ?> getApplicationConfigurable() { + private CloudApplicationConfigurable getApplicationConfigurable() { RemoteServer<?> account = getSelectedAccount(); if (account == null) { return null; } - return myCloudType2ApplicationConfigurable.get(account.getType()); + return myModuleBuilder.getContribution(account.getType()).getApplicationConfigurable(myProject, myParentDisposable); } @Override public void updateDataModel() { myModuleBuilder.setAccount(myAccountSelectionPanel.getSelectedAccount()); - CloudApplicationConfigurable<?, ?, ?, ?> configurable = getApplicationConfigurable(); + CloudApplicationConfigurable configurable = getApplicationConfigurable(); myModuleBuilder.setApplicationConfiguration(configurable == null ? null : configurable.createConfiguration()); } @Override public boolean validate() throws ConfigurationException { myAccountSelectionPanel.validate(); - CloudApplicationConfigurable<?, ?, ?, ?> configurable = getApplicationConfigurable(); + CloudApplicationConfigurable configurable = getApplicationConfigurable(); if (configurable != null) { configurable.validate(); } diff --git a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudSourceApplicationConfigurable.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudSourceApplicationConfigurable.java new file mode 100644 index 000000000000..b6e0dfc857b0 --- /dev/null +++ b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudSourceApplicationConfigurable.java @@ -0,0 +1,165 @@ +/* + * Copyright 2000-2014 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.remoteServer.impl.module; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.remoteServer.configuration.RemoteServer; +import com.intellij.remoteServer.runtime.Deployment; +import com.intellij.remoteServer.runtime.ServerConnection; +import com.intellij.remoteServer.runtime.ServerConnector; +import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance; +import com.intellij.remoteServer.util.*; +import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicReference; + + +public abstract class CloudSourceApplicationConfigurable< + SC extends CloudConfigurationBase, + DC extends CloudDeploymentNameConfiguration, + SR extends CloudMultiSourceServerRuntimeInstance<DC, ?, ?, ?>, + AC extends CloudApplicationConfiguration> extends CloudApplicationConfigurable { + + private final Project myProject; + private final Disposable myParentDisposable; + + private DelayedRunner myRunner; + + private RemoteServer<?> myAccount; + + public CloudSourceApplicationConfigurable(@Nullable Project project, Disposable parentDisposable) { + myProject = project; + myParentDisposable = parentDisposable; + } + + @Override + public void setAccount(RemoteServer<?> account) { + myAccount = account; + clearCloudData(); + } + + protected RemoteServer<SC> getAccount() { + return (RemoteServer<SC>)myAccount; + } + + @Override + public JComponent getComponent() { + JComponent result = getMainPanel(); + if (myRunner == null) { + myRunner = new DelayedRunner(result) { + + private RemoteServer<?> myPreviousAccount; + + @Override + protected boolean wasChanged() { + boolean result = myPreviousAccount != myAccount; + if (result) { + myPreviousAccount = myAccount; + } + return result; + } + + @Override + protected void run() { + loadCloudData(); + } + }; + Disposer.register(myParentDisposable, myRunner); + } + return result; + } + + protected void clearCloudData() { + getExistingComboBox().removeAllItems(); + } + + protected void loadCloudData() { + new ConnectionTask<Collection<Deployment>>("Loading existing applications list") { + + @Override + protected void run(final ServerConnection<DC> connection, + final Semaphore semaphore, + final AtomicReference<Collection<Deployment>> result) { + connection.connectIfNeeded(new ServerConnector.ConnectionCallback<DC>() { + + @Override + public void connected(@NotNull ServerRuntimeInstance<DC> serverRuntimeInstance) { + connection.computeDeployments(new Runnable() { + + @Override + public void run() { + result.set(connection.getDeployments()); + semaphore.up(); + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + if (!Disposer.isDisposed(myParentDisposable)) { + setupExistingApplications(result.get()); + } + } + }); + } + }); + } + + @Override + public void errorOccurred(@NotNull String errorMessage) { + runtimeErrorOccurred(errorMessage); + semaphore.up(); + } + }); + } + + @Override + protected Collection<Deployment> run(SR serverRuntimeInstance) throws ServerRuntimeException { + return null; + } + }.performAsync(); + } + + private void setupExistingApplications(Collection<Deployment> deployments) { + JComboBox existingComboBox = getExistingComboBox(); + existingComboBox.removeAllItems(); + for (Deployment deployment : deployments) { + existingComboBox.addItem(deployment.getName()); + } + } + + protected Project getProject() { + return myProject; + } + + protected abstract JComboBox getExistingComboBox(); + + protected abstract JComponent getMainPanel(); + + @Override + public abstract AC createConfiguration(); + + protected abstract class ConnectionTask<T> extends CloudConnectionTask<T, SC, DC, SR> { + + public ConnectionTask(String title) { + super(myProject, title, CloudSourceApplicationConfigurable.this.getAccount()); + } + } +} diff --git a/java/jsp-openapi/src/com/intellij/psi/jsp/JspImplicitVariable.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudSourceApplicationConfiguration.java index 921cc8055dd1..b1a3df6099ab 100644 --- a/java/jsp-openapi/src/com/intellij/psi/jsp/JspImplicitVariable.java +++ b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudSourceApplicationConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,18 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.psi.jsp; +package com.intellij.remoteServer.impl.module; -import com.intellij.pom.Navigatable; -import com.intellij.psi.ImplicitVariable; -import com.intellij.psi.PsiElement; -import com.intellij.navigation.NavigationItem; -public interface JspImplicitVariable extends ImplicitVariable, NavigationItem { - JspImplicitVariable[] EMPTY_ARRAY = new JspImplicitVariable[0]; - int INSIDE = 1; - int AFTER = 2; - int getDeclarationRange(); +public abstract class CloudSourceApplicationConfiguration extends CloudApplicationConfiguration { - PsiElement getDeclaration(); -}
\ No newline at end of file + private boolean myExisting; + private final String myExistingAppName; + + protected CloudSourceApplicationConfiguration(boolean existing, String existingAppName) { + myExisting = existing; + myExistingAppName = existingAppName; + } + + public boolean isExisting() { + return myExisting; + } + + public String getExistingAppName() { + return myExistingAppName; + } +} diff --git a/java/testFramework/src/com/intellij/debugger/impl/DescriptorTestCase.java b/java/testFramework/src/com/intellij/debugger/impl/DescriptorTestCase.java index 49db796244dd..7e3c5f9cd55d 100644 --- a/java/testFramework/src/com/intellij/debugger/impl/DescriptorTestCase.java +++ b/java/testFramework/src/com/intellij/debugger/impl/DescriptorTestCase.java @@ -184,23 +184,24 @@ public abstract class DescriptorTestCase extends DebuggerTestCase { for(int i = 0; i < tree.getRowCount(); i++) { final TreeNode treeNode = (TreeNode)tree.getPathForRow(i).getLastPathComponent(); if(tree.isCollapsed(i) && !treeNode.isLeaf()) { + NodeDescriptor nodeDescriptor = null; if (treeNode instanceof DebuggerTreeNodeImpl) { - final NodeDescriptor nodeDescriptor = ((DebuggerTreeNodeImpl)treeNode).getDescriptor(); - boolean shouldExpand = filter == null || filter.shouldExpand(treeNode); - if (shouldExpand) { - // additional checks to prevent infinite expand - if (nodeDescriptor instanceof ValueDescriptor) { - final Value value = ((ValueDescriptor)nodeDescriptor).getValue(); - shouldExpand = !alreadyExpanded.contains(value); - if (shouldExpand) { - alreadyExpanded.add(value); - } + nodeDescriptor = ((DebuggerTreeNodeImpl)treeNode).getDescriptor(); + } + boolean shouldExpand = filter == null || filter.shouldExpand(treeNode); + if (shouldExpand) { + // additional checks to prevent infinite expand + if (nodeDescriptor instanceof ValueDescriptor) { + final Value value = ((ValueDescriptor)nodeDescriptor).getValue(); + shouldExpand = !alreadyExpanded.contains(value); + if (shouldExpand) { + alreadyExpanded.add(value); } } - if (shouldExpand) { - anyCollapsed = true; - tree.expandRow(i); - } + } + if (shouldExpand) { + anyCollapsed = true; + tree.expandRow(i); } } } diff --git a/java/testFramework/src/com/intellij/find/FindManagerTestUtils.java b/java/testFramework/src/com/intellij/find/FindManagerTestUtils.java index 087180bbc9a3..b65b58b8638c 100644 --- a/java/testFramework/src/com/intellij/find/FindManagerTestUtils.java +++ b/java/testFramework/src/com/intellij/find/FindManagerTestUtils.java @@ -24,12 +24,10 @@ public class FindManagerTestUtils { } public static void runFindInCommentsAndLiterals(FindManager findManager, FindModel findModel, String text, String ext) { - findModel.setInStringLiteralsOnly(true); - findModel.setInCommentsOnly(false); + findModel.setSearchContext(FindModel.SearchContext.IN_STRING_LITERALS); runFindForwardAndBackward(findManager, findModel, text, ext); - findModel.setInStringLiteralsOnly(false); - findModel.setInCommentsOnly(true); + findModel.setSearchContext(FindModel.SearchContext.IN_COMMENTS); runFindForwardAndBackward(findManager, findModel, text, ext); } |