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 219678ffadbe..a4dc856755bd 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -1304,11 +1304,14 @@ public class BuildManager implements ApplicationComponent{ // this will ensure that we'll be able to obtain VirtualFile for existing roots CompilerUtil.refreshOutputDirectories(rootFiles, false); - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); final LocalFileSystem lfs = LocalFileSystem.getInstance(); final Set filesToRefresh = new HashSet(); ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { + if (project.isDisposed()) { + return; + } + final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); for (File root : rootFiles) { final VirtualFile rootFile = lfs.findFileByIoFile(root); if (rootFile != null && fileIndex.isInSourceContent(rootFile)) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java index f35dafc1d666..93e1ff136ad1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java @@ -27,19 +27,12 @@ import com.intellij.debugger.engine.evaluation.expression.Modifier; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.VirtualMachineProxyImpl; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.JdkVersionUtil; -import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler; -import com.intellij.util.PathsList; import com.sun.jdi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.org.objectweb.asm.ClassReader; @@ -55,9 +48,9 @@ import java.util.*; /** * @author egor */ -public class CompilingEvaluator implements ExpressionEvaluator { - @NotNull private final PsiElement myPsiContext; - @NotNull private final ExtractLightMethodObjectHandler.ExtractedData myData; +public abstract class CompilingEvaluator implements ExpressionEvaluator { + @NotNull protected final PsiElement myPsiContext; + @NotNull protected final ExtractLightMethodObjectHandler.ExtractedData myData; public CompilingEvaluator(@NotNull PsiElement context, @NotNull ExtractLightMethodObjectHandler.ExtractedData data) { myPsiContext = context; @@ -203,25 +196,8 @@ public class CompilingEvaluator implements ExpressionEvaluator { //private static final String GEN_CLASS_FULL_NAME = GEN_CLASS_PACKAGE + '.' + GEN_CLASS_NAME; //private static final String GEN_METHOD_NAME = "invoke"; - private String getClassCode() { - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return myData.getGeneratedInnerClass().getContainingFile().getText(); - } - }); - } - private String getMainClassName() { - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return FileUtil.getNameWithoutExtension(myData.getGeneratedInnerClass().getContainingFile().getName()); - } - }); - } - - private String getGenClassQName() { + protected String getGenClassQName() { return ApplicationManager.getApplication().runReadAction(new Computable() { @Override public String compute() { @@ -250,57 +226,13 @@ public class CompilingEvaluator implements ExpressionEvaluator { ///////////////// Compiler stuff @NotNull - private Collection compile(String target) throws EvaluateException { - if (!SystemInfo.isJavaVersionAtLeast(target)) { - throw new EvaluateException("Unable to compile for target level " + target + ". Need to run IDEA on java version at least " + target + ", currently running on " + SystemInfo.JAVA_RUNTIME_VERSION); - } - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - MemoryFileManager manager = new MemoryFileManager(compiler); - DiagnosticCollector diagnostic = new DiagnosticCollector(); - Module module = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Module compute() { - return ModuleUtilCore.findModuleForPsiElement(myPsiContext); - } - }); - List options = new ArrayList(); - if (module != null) { - options.add("-cp"); - PathsList cp = ModuleRootManager.getInstance(module).orderEntries().compileOnly().recursively().exportedOnly().withoutSdk().getPathsList(); - options.add(cp.getPathsString()); - } - if (!StringUtil.isEmpty(target)) { - options.add("-source"); - options.add(target); - options.add("-target"); - options.add(target); - } - try { - if (!compiler.getTask(null, - manager, - diagnostic, - options, - null, - Collections.singletonList(new SourceFileObject(getMainClassName(), JavaFileObject.Kind.SOURCE, getClassCode())) - ).call()) { - StringBuilder res = new StringBuilder("Compilation failed:\n"); - for (Diagnostic d : diagnostic.getDiagnostics()) { - res.append(d); - } - throw new EvaluateException(res.toString()); - } - } - catch (Exception e) { - throw new EvaluateException(e.getMessage()); - } - return manager.classes; - } + protected abstract Collection compile(String target) throws EvaluateException; private static URI getUri(String name, JavaFileObject.Kind kind) { return URI.create("memo:///" + name.replace('.', '/') + kind.extension); } - private static class SourceFileObject extends SimpleJavaFileObject { + protected static class SourceFileObject extends SimpleJavaFileObject { private final String myContent; SourceFileObject(String name, Kind kind, String content) { @@ -314,7 +246,7 @@ public class CompilingEvaluator implements ExpressionEvaluator { } } - private static class OutputFileObject extends SimpleJavaFileObject { + protected static class OutputFileObject extends SimpleJavaFileObject { private final ByteArrayOutputStream myStream = new ByteArrayOutputStream(); private final String myOrigName; @@ -333,8 +265,8 @@ public class CompilingEvaluator implements ExpressionEvaluator { } } - private static class MemoryFileManager extends ForwardingJavaFileManager { - private final Collection classes = new ArrayList(); + protected static class MemoryFileManager extends ForwardingJavaFileManager { + protected final Collection classes = new ArrayList(); MemoryFileManager(JavaCompiler compiler) { super(compiler.getStandardFileManager(null, null, null)); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluatorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluatorImpl.java new file mode 100644 index 000000000000..e7e2b8d62e5b --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluatorImpl.java @@ -0,0 +1,109 @@ +/* + * 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.debugger.ui.impl.watch; + +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler; +import com.intellij.util.PathsList; +import org.jetbrains.annotations.NotNull; + +import javax.tools.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class CompilingEvaluatorImpl extends CompilingEvaluator { + + public CompilingEvaluatorImpl(@NotNull PsiElement context, @NotNull ExtractLightMethodObjectHandler.ExtractedData data) { + super(context, data); + } + + @Override + @NotNull + protected Collection compile(String target) throws EvaluateException { + if (!SystemInfo.isJavaVersionAtLeast(target)) { + throw new EvaluateException("Unable to compile for target level " + target + ". Need to run IDEA on java version at least " + target + ", currently running on " + SystemInfo.JAVA_RUNTIME_VERSION); + } + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + MemoryFileManager manager = new MemoryFileManager(compiler); + DiagnosticCollector diagnostic = new DiagnosticCollector(); + Module module = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Module compute() { + return ModuleUtilCore.findModuleForPsiElement(myPsiContext); + } + }); + List options = new ArrayList(); + if (module != null) { + options.add("-cp"); + PathsList cp = ModuleRootManager.getInstance(module).orderEntries().compileOnly().recursively().exportedOnly().withoutSdk().getPathsList(); + options.add(cp.getPathsString()); + } + if (!StringUtil.isEmpty(target)) { + options.add("-source"); + options.add(target); + options.add("-target"); + options.add(target); + } + try { + if (!compiler.getTask(null, + manager, + diagnostic, + options, + null, + Collections.singletonList(new SourceFileObject(getMainClassName(), JavaFileObject.Kind.SOURCE, getClassCode())) + ).call()) { + StringBuilder res = new StringBuilder("Compilation failed:\n"); + for (Diagnostic d : diagnostic.getDiagnostics()) { + res.append(d); + } + throw new EvaluateException(res.toString()); + } + } + catch (Exception e) { + throw new EvaluateException(e.getMessage()); + } + return manager.classes; + } + + protected String getClassCode() { + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public String compute() { + return myData.getGeneratedInnerClass().getContainingFile().getText(); + } + }); + } + + protected String getMainClassName() { + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public String compute() { + return FileUtil.getNameWithoutExtension(myData.getGeneratedInnerClass().getContainingFile().getName()); + } + }); + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java index 20708864c104..f26d81292e35 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.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. @@ -101,7 +101,7 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl{ ExtractLightMethodObjectHandler.ExtractedData data = ExtractLightMethodObjectHandler.extractLightMethodObject(myProject, psiFile, fragment, CompilingEvaluator.getGeneratedClassName()); if (data != null) { - return new CompilingEvaluator(psiContext, data); + return new CompilingEvaluatorImpl(psiContext, data); } } catch (PrepareFailedException e) { diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/SimpleGetterProvider.java b/java/debugger/openapi/src/com/intellij/debugger/engine/SimpleGetterProvider.java index b776d91e2174..452d49e7f558 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/SimpleGetterProvider.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/SimpleGetterProvider.java @@ -22,7 +22,7 @@ import com.intellij.psi.*; * Nikolay.Tropin * 2014-11-25 */ -interface SimpleGetterProvider { +public interface SimpleGetterProvider { ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.debugger.simpleGetterProvider"); boolean isSimpleGetter(PsiMethod method); diff --git a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java index 4d948dae8a2d..c13f76791f65 100644 --- a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java +++ b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java @@ -136,7 +136,7 @@ public class JavaParametersUtil { } final boolean isJdk = JavaSdk.checkForJdk(new File(jreHome)); if (isJdk) { - throw new CantRunException("Jre expected but jdk found"); + throw new CantRunException("Alternative JRE path needs to point to a JRE, not to a complete JDK installation"); } final Sdk jdk = JavaSdk.getInstance().createJdk("", jreHome); if (jdk == null) throw CantRunException.noJdkConfigured(); 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 6c281b0def27..89de3dec0b24 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 @@ -109,6 +109,13 @@ public abstract class FrameworkSupportModelBase extends UserDataHolderBase imple node.setChecked(enable); // ensure configurable to be created and registered to disposer node.getConfigurable(); + if (myFrameworkVersions.get(providerId) == null) { + for (FrameworkVersion version : node.getUserObject().getFrameworkType().getVersions()) { + if (version.getAvailabilityCondition().isAvailableFor(this)) { + setSelectedVersion(providerId, version); + } + } + } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java index 7ba14c2367bb..c67d4c995b1f 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java @@ -48,22 +48,22 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { } } - if (!ignoreInference(listOwner, annotationFQN)) { - PsiAnnotation fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotation(listOwner, annotationFQN); - if (fromBytecode != null) { - return fromBytecode; - } + if (ignoreInference(listOwner, annotationFQN)) { + return null; + } + + PsiAnnotation fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotation(listOwner, annotationFQN); + if (fromBytecode != null) { + return fromBytecode; } - if (canInferFromSource(listOwner)) { - //noinspection ConstantConditions - PsiMethod method = (PsiMethod)listOwner; + if (listOwner instanceof PsiMethod) { if (ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotationFQN)) { - return getInferredContractAnnotation(method); + return getInferredContractAnnotation((PsiMethod)listOwner); } - + if ((AnnotationUtil.NOT_NULL.equals(annotationFQN) || AnnotationUtil.NULLABLE.equals(annotationFQN))) { - PsiAnnotation anno = getInferredNullityAnnotation(method); + PsiAnnotation anno = getInferredNullityAnnotation((PsiMethod)listOwner); return anno == null ? null : annotationFQN.equals(anno.getQualifiedName()) ? anno : null; } } @@ -79,6 +79,9 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { @Override public boolean ignoreInference(@NotNull PsiModifierListOwner owner, @Nullable String annotationFQN) { + if (owner instanceof PsiMethod && PsiUtil.canBeOverriden((PsiMethod)owner)) { + return true; + } if (ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotationFQN) && hasHardcodedContracts(owner)) { return true; } @@ -138,10 +141,6 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { return ProjectBytecodeAnalysis.getInstance(myProject).createContractAnnotation(attrs); } - private static boolean canInferFromSource(PsiModifierListOwner listOwner) { - return listOwner instanceof PsiMethod && !PsiUtil.canBeOverriden((PsiMethod)listOwner); - } - @NotNull @Override public PsiAnnotation[] findInferredAnnotations(@NotNull PsiModifierListOwner listOwner) { @@ -150,17 +149,24 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { PsiAnnotation[] fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotations(listOwner); for (PsiAnnotation annotation : fromBytecode) { if (!ignoreInference(listOwner, annotation.getQualifiedName())) { - if (!ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotation.getQualifiedName()) || canInferFromSource(listOwner)) { - result.add(annotation); - } + result.add(annotation); } } - if (canInferFromSource(listOwner)) { + if (listOwner instanceof PsiMethod) { PsiAnnotation hardcoded = getHardcodedContractAnnotation((PsiMethod)listOwner); - ContainerUtil.addIfNotNull(result, hardcoded != null ? hardcoded : getInferredContractAnnotation((PsiMethod)listOwner)); - - ContainerUtil.addIfNotNull(result, getInferredNullityAnnotation((PsiMethod)listOwner)); + if (hardcoded != null) { + result.add(hardcoded); + } else if (!ignoreInference(listOwner, ORG_JETBRAINS_ANNOTATIONS_CONTRACT)) { + ContainerUtil.addIfNotNull(result, getInferredContractAnnotation((PsiMethod)listOwner)); + } + + if (!ignoreInference(listOwner, AnnotationUtil.NOT_NULL) || !ignoreInference(listOwner, AnnotationUtil.NULLABLE)) { + PsiAnnotation annotation = getInferredNullityAnnotation((PsiMethod)listOwner); + if (annotation != null && !ignoreInference(listOwner, annotation.getQualifiedName())) { + result.add(annotation); + } + } } return result.isEmpty() ? PsiAnnotation.EMPTY_ARRAY : result.toArray(new PsiAnnotation[result.size()]); 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 16ee467c63ed..e90211e581f5 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 @@ -89,8 +89,12 @@ class ContractInferenceInterpreter { PsiTypeElement typeElement = myMethod.getReturnTypeElement(); final PsiType returnType = typeElement == null ? null : typeElement.getType(); - final boolean notNull = !(returnType instanceof PsiPrimitiveType) && + boolean referenceTypeReturned = !(returnType instanceof PsiPrimitiveType); + final boolean notNull = referenceTypeReturned && NullableNotNullManager.getInstance(myMethod.getProject()).isNotNull(myMethod, false); + if (referenceTypeReturned) { + contracts = boxReturnValues(contracts); + } return ContainerUtil.filter(contracts, new Condition() { @Override public boolean value(MethodContract contract) { @@ -101,7 +105,20 @@ class ContractInferenceInterpreter { } }); } - + + @NotNull + private static List boxReturnValues(List contracts) { + return ContainerUtil.mapNotNull(contracts, new Function() { + @Override + public MethodContract fun(MethodContract contract) { + if (contract.returnValue == FALSE_VALUE || contract.returnValue == TRUE_VALUE) { + return new MethodContract(contract.arguments, NOT_NULL_VALUE); + } + return contract; + } + }); + } + private List doInferContracts() { PsiCodeBlock body = myMethod.getBody(); PsiStatement[] statements = body == null ? PsiStatement.EMPTY_ARRAY : body.getStatements(); @@ -294,7 +311,7 @@ class ContractInferenceInterpreter { parameter = resolveParameter(op2); constraint = getLiteralConstraint(op1); } - if (parameter >= 0 && constraint != null) { + if (parameter >= 0 && constraint != null && constraint != NOT_NULL_VALUE) { List result = ContainerUtil.newArrayList(); for (ValueConstraint[] state : states) { ContainerUtil.addIfNotNull(result, contractWithConstraint(state, parameter, constraint, equality ? TRUE_VALUE : FALSE_VALUE)); @@ -410,7 +427,7 @@ class ContractInferenceInterpreter { if (expr.textMatches(PsiKeyword.TRUE)) return TRUE_VALUE; if (expr.textMatches(PsiKeyword.FALSE)) return FALSE_VALUE; if (expr.textMatches(PsiKeyword.NULL)) return NULL_VALUE; - if (((PsiLiteralExpression)expr).getValue() instanceof String) return NOT_NULL_VALUE; + return NOT_NULL_VALUE; } return null; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 09d693ee7aab..e90611f372b2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -1490,10 +1490,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { final PsiAnnotation contractAnno = findContractAnnotation(method); final int paramCount = method.getParameterList().getParametersCount(); if (contractAnno != null) { - if (AnnotationUtil.isInferredAnnotation(contractAnno) && PsiUtil.canBeOverriden(method)) { - return Collections.emptyList(); - } - return CachedValuesManager.getCachedValue(contractAnno, new CachedValueProvider>() { @Nullable @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java index f48303bd85ac..3403ed5584d9 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java @@ -536,6 +536,10 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { } private static boolean isCompileConstantInIfCondition(PsiElement element) { + if (element instanceof PsiPrefixExpression && ((PsiPrefixExpression)element).getOperationTokenType() == JavaTokenType.EXCL) { + return isCompileConstantInIfCondition(((PsiPrefixExpression)element).getOperand()); + } + if (!(element instanceof PsiReferenceExpression)) return false; PsiElement resolved = ((PsiReferenceExpression)element).resolve(); if (!(resolved instanceof PsiField)) return false; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index 8b2beae6d5d9..a1a1f142d1a3 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -253,10 +253,6 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (value instanceof DfaVariableValue) { setVariableState(var, getVariableState((DfaVariableValue)value)); } - else if (value instanceof DfaBoxedValue) { - setVariableState(var, getVariableState(var).withNullable(false)); - applyCondition(compareToNull(var, true)); - } } if (getVariableState(var).isNotNull()) { @@ -477,6 +473,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { @Override public boolean isNotNull(DfaValue dfaVar) { if (dfaVar instanceof DfaConstValue) return ((DfaConstValue)dfaVar).getValue() != null; + if (dfaVar instanceof DfaBoxedValue) return true; if (dfaVar instanceof DfaTypeValue) return ((DfaTypeValue)dfaVar).isNotNull(); if (dfaVar instanceof DfaVariableValue) { if (getVariableState((DfaVariableValue)dfaVar).isNotNull()) return true; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java index 64d123f6beac..e77a9478334b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java @@ -26,7 +26,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -68,25 +68,34 @@ public class NullityInference { final AtomicBoolean hasNotNulls = new AtomicBoolean(); final AtomicBoolean hasNulls = new AtomicBoolean(); final AtomicBoolean hasUnknowns = new AtomicBoolean(); - final List calls = ContainerUtil.newArrayList(); + final Set delegates = ContainerUtil.newLinkedHashSet(); body.accept(new JavaRecursiveElementWalkingVisitor() { @Override public void visitReturnStatement(PsiReturnStatement statement) { PsiExpression value = statement.getReturnValue(); if (value == null) { hasErrors.set(true); - } else { - if (value instanceof PsiLiteralExpression) { - if (value.textMatches(PsiKeyword.NULL)) { - hasNulls.set(true); - } else { - hasNotNulls.set(true); - } - } else if (value instanceof PsiMethodCallExpression) { - calls.add((PsiMethodCallExpression)value); - } else { - hasUnknowns.set(true); + } else if (value instanceof PsiLiteralExpression) { + if (value.textMatches(PsiKeyword.NULL)) { + hasNulls.set(true); } + else { + hasNotNulls.set(true); + } + } + else if (value.getType() instanceof PsiPrimitiveType) { + hasNotNulls.set(true); + } + else if (value instanceof PsiMethodCallExpression) { + PsiMethod target = ((PsiMethodCallExpression)value).resolveMethod(); + if (target == null) { + hasUnknowns.set(true); + } else { + delegates.add(target); + } + } + else { + hasUnknowns.set(true); } super.visitReturnStatement(statement); } @@ -102,13 +111,12 @@ public class NullityInference { return Nullness.NULLABLE; } - if (calls.size() > 1) { + if (hasErrors.get() || delegates.size() > 1) { return Nullness.UNKNOWN; } - if (calls.size() == 1) { - PsiMethod target = calls.get(0).resolveMethod(); - if (target != null && NullableNotNullManager.isNotNull(target)) { + if (delegates.size() == 1) { + if (NullableNotNullManager.isNotNull(delegates.iterator().next())) { return Nullness.NOT_NULL; } return Nullness.UNKNOWN; diff --git a/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/InputVariables.java b/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/InputVariables.java index 369613c46040..f0ba3799be5c 100644 --- a/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/InputVariables.java +++ b/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/InputVariables.java @@ -33,6 +33,7 @@ import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.util.VariableData; import com.intellij.refactoring.util.duplicates.DuplicatesFinder; import com.intellij.util.ArrayUtil; +import com.intellij.util.text.UniqueNameGenerator; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -47,6 +48,9 @@ public class InputVariables { private ParametersFolder myFolding; private boolean myFoldingAvailable; + private Set myUsedInstanceFields = null; + private boolean myPassFields = false; + public InputVariables(final List inputVariables, Project project, LocalSearchScope scope, @@ -74,16 +78,25 @@ public class InputVariables { return myFolding.isFoldable(); } + public void setUsedInstanceFields(Set usedInstanceFields) { + myUsedInstanceFields = usedInstanceFields; + } + + public void setPassFields(boolean passFields) { + if (myUsedInstanceFields == null || myUsedInstanceFields.isEmpty()) { + return; + } + myPassFields = passFields; + + myInputVariables.clear(); + myInputVariables.addAll(wrapInputVariables(myInitialParameters)); + } + public ArrayList wrapInputVariables(final List inputVariables) { + UniqueNameGenerator nameGenerator = new UniqueNameGenerator(); final ArrayList inputData = new ArrayList(inputVariables.size()); for (PsiVariable var : inputVariables) { - String name = var.getName(); - if (!(var instanceof PsiParameter)) { - JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(myProject); - VariableKind kind = codeStyleManager.getVariableKind(var); - name = codeStyleManager.variableNameToPropertyName(name, kind); - name = codeStyleManager.propertyNameToVariableName(name, VariableKind.PARAMETER); - } + String name = nameGenerator.generateUniqueName(getParameterName(var)); PsiType type = var.getType(); if (type instanceof PsiEllipsisType) { type = ((PsiEllipsisType)type).toArrayType(); @@ -138,9 +151,28 @@ public class InputVariables { } + if (myPassFields && myUsedInstanceFields != null) { + for (PsiField var : myUsedInstanceFields) { + final VariableData data = new VariableData(var, var.getType()); + data.name = nameGenerator.generateUniqueName(getParameterName(var)); + data.passAsParameter = true; + inputData.add(data); + } + } return inputData; } + private String getParameterName(PsiVariable var) { + String name = var.getName(); + if (!(var instanceof PsiParameter)) { + JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(myProject); + VariableKind kind = codeStyleManager.getVariableKind(var); + name = codeStyleManager.variableNameToPropertyName(name, kind); + name = codeStyleManager.propertyNameToVariableName(name, VariableKind.PARAMETER); + } + return name; + } + @Nullable private PsiType checkTopLevelInstanceOf(final PsiType currentType) { final PsiElement[] scope = myScope.getScope(); @@ -310,4 +342,8 @@ public class InputVariables { public boolean isFoldingSelectedByDefault() { return myFolding.isFoldingSelectedByDefault(); } + + public boolean hasInstanceFields() { + return myUsedInstanceFields != null && !myUsedInstanceFields.isEmpty(); + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index 82f2690542d4..dd66d54a9d76 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -880,11 +880,17 @@ public class ExpectedTypesProvider { if (statement.getException() == myExpr) { PsiManager manager = statement.getManager(); PsiType throwableType = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createTypeByFQClassName("java.lang.Throwable", myExpr.getResolveScope()); - PsiMember container = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, PsiClass.class); + PsiElement container = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, PsiLambdaExpression.class, PsiClass.class); PsiType[] throwsTypes = PsiType.EMPTY_ARRAY; if (container instanceof PsiMethod) { throwsTypes = ((PsiMethod)container).getThrowsList().getReferencedTypes(); } + else if (container instanceof PsiLambdaExpression) { + final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(container); + if (method != null) { + throwsTypes = method.getThrowsList().getReferencedTypes(); + } + } if (throwsTypes.length == 0) { final PsiClassType exceptionType = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createTypeByFQClassName("java.lang.Exception", myExpr.getResolveScope()); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.java index 900e0563f8cd..8ab1bdf97838 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.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. @@ -67,7 +67,7 @@ public class RecursiveCallLineMarkerProvider implements LineMarkerProvider { return false; } - final PsiMethod method = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class); + final PsiMethod method = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class, true, PsiLambdaExpression.class, PsiClass.class); if (method == null || !method.getName().equals(methodCall.getMethodExpression().getReferenceName())) { return false; } diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java index 80941aabfc9e..724aab3358d0 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java @@ -25,6 +25,7 @@ import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; @@ -56,9 +57,10 @@ import com.intellij.ui.treeStructure.Tree; import com.intellij.util.*; import com.intellij.util.ui.DialogUtil; import com.intellij.util.ui.UIUtil; -import com.intellij.util.ui.table.JBListTable; +import com.intellij.util.ui.table.EditorTextFieldJBTableRowRenderer; import com.intellij.util.ui.table.JBTableRow; import com.intellij.util.ui.table.JBTableRowEditor; +import com.intellij.util.ui.table.JBTableRowRenderer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -72,6 +74,7 @@ import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Set; import static com.intellij.refactoring.changeSignature.ChangeSignatureHandler.REFACTORING_NAME; @@ -220,32 +223,175 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase row) { - if (!StringUtil.isEmpty(row.parameter.getName())) return false; - if (!StringUtil.isEmpty(row.parameter.getTypeText())) return false; - return true; - } + protected ParametersListTable createParametersListTable() { + return new ParametersListTable() { + private final EditorTextFieldJBTableRowRenderer myRowRenderer = new EditorTextFieldJBTableRowRenderer(getProject(), myDisposable) { + @Override + protected String getText(JTable table, int row) { + ParameterTableModelItemBase item = getRowItem(row); + final String typeText = item.typeCodeFragment.getText(); + final String separator = StringUtil.repeatSymbol(' ', getTypesMaxLength() - typeText.length() + 1); + String text = typeText + separator + item.parameter.getName(); + final String defaultValue = item.defaultValueCodeFragment.getText(); + String tail = ""; + if (StringUtil.isNotEmpty(defaultValue)) { + tail += " default value = " + defaultValue; + } + if (item.parameter.isUseAnySingleVariable()) { + if (StringUtil.isNotEmpty(defaultValue)) { + tail += ";"; + } + tail += " Use any var."; + } + if (!StringUtil.isEmpty(tail)) { + text += " //" + tail; + } + return " " + text; + } - @Override - protected JComponent getRowPresentation(ParameterTableModelItemBase item, boolean selected, final boolean focused) { - final String typeText = item.typeCodeFragment.getText(); - final String separator = StringUtil.repeatSymbol(' ', getTypesMaxLength() - typeText.length() + 1); - String text = typeText + separator + item.parameter.getName(); - final String defaultValue = item.defaultValueCodeFragment.getText(); - String tail = ""; - if (StringUtil.isNotEmpty(defaultValue)) { - tail += " default value = " + defaultValue; - } - if (item.parameter.isUseAnySingleVariable()) { - if (StringUtil.isNotEmpty(defaultValue)) { - tail += ";"; + @Nullable + @Override + protected FileType getFileType() { + return JavaChangeSignatureDialog.this.getFileType(); + } + }; + + @Override + protected JBTableRowRenderer getRowRenderer(int row) { + return myRowRenderer; } - tail += " Use any var."; - } - if (!StringUtil.isEmpty(tail)) { - text += " //" + tail; - } - return JBListTable.createEditorTextFieldPresentation(getProject(), getFileType(), " " + text, selected, focused); + + @NotNull + @Override + protected JBTableRowEditor getRowEditor(final ParameterTableModelItemBase item) { + return new JBTableRowEditor() { + private EditorTextField myTypeEditor; + private EditorTextField myNameEditor; + private EditorTextField myDefaultValueEditor; + private JCheckBox myAnyVar; + + @Override + public void prepareEditor(JTable table, int row) { + setLayout(new BorderLayout()); + final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(item.typeCodeFragment); + myTypeEditor = new EditorTextField(document, getProject(), getFileType()); + myTypeEditor.addDocumentListener(mySignatureUpdater); + myTypeEditor.setPreferredWidth(getTable().getWidth() / 2); + myTypeEditor.addDocumentListener(new RowEditorChangeListener(0)); + add(createLabeledPanel("Type:", myTypeEditor), BorderLayout.WEST); + + myNameEditor = new EditorTextField(item.parameter.getName(), getProject(), getFileType()); + myNameEditor.addDocumentListener(mySignatureUpdater); + myNameEditor.addDocumentListener(new RowEditorChangeListener(1)); + add(createLabeledPanel("Name:", myNameEditor), BorderLayout.CENTER); + new TextFieldCompletionProvider() { + + @Override + protected void addCompletionVariants(@NotNull String text, + int offset, + @NotNull String prefix, + @NotNull CompletionResultSet result) { + final PsiCodeFragment fragment = item.typeCodeFragment; + if (fragment instanceof PsiTypeCodeFragment) { + final PsiType type; + try { + type = ((PsiTypeCodeFragment)fragment).getType(); + } + catch (Exception e) { + return; + } + final SuggestedNameInfo info = JavaCodeStyleManager.getInstance(myProject) + .suggestVariableName(VariableKind.PARAMETER, null, null, type); + + for (String completionVariant : info.names) { + final LookupElementBuilder element = LookupElementBuilder.create(completionVariant); + result.addElement(element.withLookupString(completionVariant.toLowerCase(Locale.ENGLISH))); + } + } + } + }.apply(myNameEditor, item.parameter.getName()); + + if (!item.isEllipsisType() && item.parameter.getOldIndex() == -1) { + final JPanel additionalPanel = new JPanel(new BorderLayout()); + final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(item.defaultValueCodeFragment); + myDefaultValueEditor = new EditorTextField(doc, getProject(), getFileType()); + ((PsiExpressionCodeFragment)item.defaultValueCodeFragment).setExpectedType(getRowType(item)); + myDefaultValueEditor.setPreferredWidth(getTable().getWidth() / 2); + myDefaultValueEditor.addDocumentListener(new RowEditorChangeListener(2)); + additionalPanel.add(createLabeledPanel("Default value:", myDefaultValueEditor), BorderLayout.WEST); + + if (!isGenerateDelegate()) { + myAnyVar = new JCheckBox("&Use Any Var"); + UIUtil.applyStyle(UIUtil.ComponentStyle.SMALL, myAnyVar); + DialogUtil.registerMnemonic(myAnyVar, '&'); + myAnyVar.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + item.parameter.setUseAnySingleVariable(myAnyVar.isSelected()); + } + }); + final JPanel anyVarPanel = new JPanel(new BorderLayout()); + anyVarPanel.add(myAnyVar, BorderLayout.SOUTH); + UIUtil.addInsets(anyVarPanel, new Insets(0,0,8,0)); + additionalPanel.add(anyVarPanel, BorderLayout.CENTER); + //additionalPanel.setPreferredSize(new Dimension(t.getWidth() / 3, -1)); + } + add(additionalPanel, BorderLayout.SOUTH); + } + } + + @Override + public JBTableRow getValue() { + return new JBTableRow() { + @Override + public Object getValueAt(int column) { + switch (column) { + case 0: return item.typeCodeFragment; + case 1: return myNameEditor.getText().trim(); + case 2: return item.defaultValueCodeFragment; + case 3: return myAnyVar != null && myAnyVar.isSelected(); + } + return null; + } + }; + } + + @Override + public JComponent getPreferredFocusedComponent() { + final MouseEvent me = getMouseEvent(); + if (me == null) { + return myTypeEditor.getFocusTarget(); + } + final double x = me.getPoint().getX(); + return x <= getTypesColumnWidth() + ? myTypeEditor.getFocusTarget() + : myDefaultValueEditor == null || x <= getNamesColumnWidth() + ? myNameEditor.getFocusTarget() + : myDefaultValueEditor.getFocusTarget(); + } + + @Override + public JComponent[] getFocusableComponents() { + final List focusable = new ArrayList(); + focusable.add(myTypeEditor.getFocusTarget()); + focusable.add(myNameEditor.getFocusTarget()); + if (myDefaultValueEditor != null) { + focusable.add(myDefaultValueEditor.getFocusTarget()); + } + if (myAnyVar != null) { + focusable.add(myAnyVar); + } + return focusable.toArray(new JComponent[focusable.size()]); + } + }; + } + + @Override + protected boolean isRowEmpty(int row) { + ParameterInfoImpl parameter = getRowItem(row).parameter; + return StringUtil.isEmpty(parameter.getName()) && StringUtil.isEmpty(parameter.getTypeText()); + } + }; } private int getTypesMaxLength() { @@ -281,130 +427,6 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase item) { - return new JBTableRowEditor() { - private EditorTextField myTypeEditor; - private EditorTextField myNameEditor; - private EditorTextField myDefaultValueEditor; - private JCheckBox myAnyVar; - - @Override - public void prepareEditor(JTable table, int row) { - setLayout(new BorderLayout()); - final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(item.typeCodeFragment); - myTypeEditor = new EditorTextField(document, getProject(), getFileType()); - myTypeEditor.addDocumentListener(mySignatureUpdater); - myTypeEditor.setPreferredWidth(t.getWidth() / 2); - myTypeEditor.addDocumentListener(new RowEditorChangeListener(0)); - add(createLabeledPanel("Type:", myTypeEditor), BorderLayout.WEST); - - myNameEditor = new EditorTextField(item.parameter.getName(), getProject(), getFileType()); - myNameEditor.addDocumentListener(mySignatureUpdater); - myNameEditor.addDocumentListener(new RowEditorChangeListener(1)); - add(createLabeledPanel("Name:", myNameEditor), BorderLayout.CENTER); - new TextFieldCompletionProvider() { - - @Override - protected void addCompletionVariants(@NotNull String text, - int offset, - @NotNull String prefix, - @NotNull CompletionResultSet result) { - final PsiCodeFragment fragment = item.typeCodeFragment; - if (fragment instanceof PsiTypeCodeFragment) { - final PsiType type; - try { - type = ((PsiTypeCodeFragment)fragment).getType(); - } - catch (Exception e) { - return; - } - final SuggestedNameInfo info = JavaCodeStyleManager.getInstance(myProject) - .suggestVariableName(VariableKind.PARAMETER, null, null, type); - - for (String completionVariant : info.names) { - final LookupElementBuilder element = LookupElementBuilder.create(completionVariant); - result.addElement(element.withLookupString(completionVariant.toLowerCase())); - } - } - } - }.apply(myNameEditor, item.parameter.getName()); - - if (!item.isEllipsisType() && item.parameter.getOldIndex() == -1) { - final JPanel additionalPanel = new JPanel(new BorderLayout()); - final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(item.defaultValueCodeFragment); - myDefaultValueEditor = new EditorTextField(doc, getProject(), getFileType()); - ((PsiExpressionCodeFragment)item.defaultValueCodeFragment).setExpectedType(getRowType(item)); - myDefaultValueEditor.setPreferredWidth(t.getWidth() / 2); - myDefaultValueEditor.addDocumentListener(new RowEditorChangeListener(2)); - additionalPanel.add(createLabeledPanel("Default value:", myDefaultValueEditor), BorderLayout.WEST); - - if (!isGenerateDelegate()) { - myAnyVar = new JCheckBox("&Use Any Var"); - UIUtil.applyStyle(UIUtil.ComponentStyle.SMALL, myAnyVar); - DialogUtil.registerMnemonic(myAnyVar, '&'); - myAnyVar.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - item.parameter.setUseAnySingleVariable(myAnyVar.isSelected()); - } - }); - final JPanel anyVarPanel = new JPanel(new BorderLayout()); - anyVarPanel.add(myAnyVar, BorderLayout.SOUTH); - UIUtil.addInsets(anyVarPanel, new Insets(0,0,8,0)); - additionalPanel.add(anyVarPanel, BorderLayout.CENTER); - //additionalPanel.setPreferredSize(new Dimension(t.getWidth() / 3, -1)); - } - add(additionalPanel, BorderLayout.SOUTH); - } - } - - @Override - public JBTableRow getValue() { - return new JBTableRow() { - @Override - public Object getValueAt(int column) { - switch (column) { - case 0: return item.typeCodeFragment; - case 1: return myNameEditor.getText().trim(); - case 2: return item.defaultValueCodeFragment; - case 3: return myAnyVar != null && myAnyVar.isSelected(); - } - return null; - } - }; - } - - @Override - public JComponent getPreferredFocusedComponent() { - final MouseEvent me = getMouseEvent(); - if (me == null) { - return myTypeEditor.getFocusTarget(); - } - final double x = me.getPoint().getX(); - return x <= getTypesColumnWidth() - ? myTypeEditor.getFocusTarget() - : myDefaultValueEditor == null || x <= getNamesColumnWidth() - ? myNameEditor.getFocusTarget() - : myDefaultValueEditor.getFocusTarget(); - } - - @Override - public JComponent[] getFocusableComponents() { - final List focusable = new ArrayList(); - focusable.add(myTypeEditor.getFocusTarget()); - focusable.add(myNameEditor.getFocusTarget()); - if (myDefaultValueEditor != null) { - focusable.add(myDefaultValueEditor.getFocusTarget()); - } - if (myAnyVar != null) { - focusable.add(myAnyVar); - } - return focusable.toArray(new JComponent[focusable.size()]); - } - }; - } - @Nullable private static PsiType getRowType(ParameterTableModelItemBase item) { try { diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ControlFlowWrapper.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ControlFlowWrapper.java index 09f66f442276..062c1457e818 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ControlFlowWrapper.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ControlFlowWrapper.java @@ -28,6 +28,7 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.RefactoringBundle; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.IntArrayList; +import org.jetbrains.annotations.NotNull; import java.util.*; @@ -106,8 +107,8 @@ public class ControlFlowWrapper { } if (myExitPoints.size() != 1) { - areExitStatementsTheSame(); myGenerateConditionalExit = true; + areExitStatementsTheSame(); } return myExitStatements; } @@ -142,10 +143,12 @@ public class ControlFlowWrapper { public static class ExitStatementsNotSameException extends Exception {} + @NotNull public PsiVariable[] getOutputVariables() { return getOutputVariables(myGenerateConditionalExit); } + @NotNull public PsiVariable[] getOutputVariables(boolean collectVariablesAtExitPoints) { PsiVariable[] myOutputVariables = ControlFlowUtil.getOutputVariables(myControlFlow, myFlowStart, myFlowEnd, myExitPoints.toArray()); if (collectVariablesAtExitPoints) { diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java index b676f77a60ac..a2d768b7513b 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java @@ -31,6 +31,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiFormatUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.ui.*; import com.intellij.refactoring.util.ConflictsUtil; @@ -40,6 +41,7 @@ import com.intellij.ui.EditorTextField; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.NonFocusableCheckBox; import com.intellij.ui.SeparatorFactory; +import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.MultiMap; @@ -239,11 +241,28 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac return main; } + protected boolean isVoidReturn() { + return false; + } + @Nullable private JPanel createReturnTypePanel() { - mySelector = new TypeSelectorManagerImpl(myProject, myReturnType, findOccurrences(), areTypesDirected()).getTypeSelector(); + if (TypeConversionUtil.isPrimitiveWrapper(myReturnType) && myNullness == Nullness.NULLABLE) { + return null; + } + final TypeSelectorManagerImpl manager = new TypeSelectorManagerImpl(myProject, myReturnType, findOccurrences(), areTypesDirected()) { + @Override + public PsiType[] getTypesForAll(boolean direct) { + final PsiType[] types = super.getTypesForAll(direct); + return !isVoidReturn() ? types : ArrayUtil.prepend(PsiType.VOID, types); + } + }; + mySelector = manager.getTypeSelector(); final JComponent component = mySelector.getComponent(); if (component instanceof JComboBox) { + if (isVoidReturn()) { + mySelector.selectType(PsiType.VOID); + } final JPanel returnTypePanel = new JPanel(new BorderLayout(2, 0)); final JLabel label = new JLabel(RefactoringBundle.message("changeSignature.return.type.prompt")); returnTypePanel.add(label, BorderLayout.NORTH); @@ -280,8 +299,17 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac if (myStaticFlag || myCanBeStatic) { myMakeStatic.setEnabled(!myStaticFlag); myMakeStatic.setSelected(myStaticFlag); + if (myVariableData.hasInstanceFields()) { + myMakeStatic.setText(RefactoringBundle.message("declare.static.pass.fields.checkbox")); + } myMakeStatic.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { + if (myVariableData.hasInstanceFields()) { + myVariableData.setPassFields(myMakeStatic.isSelected()); + myInputVariables = myVariableData.getInputVariables().toArray(new VariableData[myVariableData.getInputVariables().size()]); + updateVarargsEnabled(); + createParametersPanel(); + } updateSignature(); } }); @@ -523,7 +551,7 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac buffer.append(myTargetClass.getName()); } else { - buffer.append(PsiFormatUtil.formatType(mySelector.getSelectedType(), 0, PsiSubstitutor.EMPTY)); + buffer.append(PsiFormatUtil.formatType(mySelector != null ? mySelector.getSelectedType() : myReturnType, 0, PsiSubstitutor.EMPTY)); buffer.append(" "); buffer.append(myNameField.getText()); } @@ -593,6 +621,6 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac } public PsiType getReturnType() { - return mySelector.getSelectedType(); + return mySelector != null ? mySelector.getSelectedType() : myReturnType; } } 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 bdeab1560188..5c9701ab8621 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -53,6 +53,8 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.controlFlow.ControlFlowUtil; import com.intellij.psi.impl.source.codeStyle.JavaCodeStyleManagerImpl; +import com.intellij.psi.scope.processor.VariablesProcessor; +import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.PsiElementProcessor; @@ -68,10 +70,8 @@ import com.intellij.refactoring.introduceVariable.IntroduceVariableBase; import com.intellij.refactoring.util.*; import com.intellij.refactoring.util.classMembers.ElementNeedsThis; import com.intellij.refactoring.util.duplicates.*; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.Processor; -import com.intellij.util.VisibilityUtil; +import com.intellij.util.*; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -114,6 +114,7 @@ public class ExtractMethodProcessor implements MatchProvider { protected InputVariables myInputVariables; // input variables protected PsiVariable[] myOutputVariables; // output variables protected PsiVariable myOutputVariable; // the only output variable + private PsiVariable myArtificialOutputVariable; private Collection myExitStatements; private boolean myHasReturnStatement; // there is a return statement @@ -125,7 +126,6 @@ public class ExtractMethodProcessor implements MatchProvider { protected boolean myCanBeStatic; protected boolean myCanBeChainedConstructor; protected boolean myIsChainedConstructor; - private DuplicatesFinder myDuplicatesFinder; private List myDuplicates; @PsiModifier.ModifierConstant private String myMethodVisibility = PsiModifier.PRIVATE; protected boolean myGenerateConditionalExit; @@ -242,8 +242,11 @@ public class ExtractMethodProcessor implements MatchProvider { } catch (ControlFlowWrapper.ExitStatementsNotSameException e) { myExitStatements = myControlFlowWrapper.getExitStatements(); - showMultipleExitPointsMessage(); - return false; + myNotNullConditionalCheck = areAllExitPointsAreNotNull(getExpectedReturnType()); + if (!myNotNullConditionalCheck) { + showMultipleExitPointsMessage(); + return false; + } } myOutputVariables = myControlFlowWrapper.getOutputVariables(); @@ -266,11 +269,7 @@ public class ExtractMethodProcessor implements MatchProvider { } myHasExpressionOutput = expressionType != PsiType.VOID; - final PsiType returnStatementType = myCodeFragmentMember instanceof PsiMethod - ? ((PsiMethod)myCodeFragmentMember).getReturnType() - : myCodeFragmentMember instanceof PsiLambdaExpression - ? LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)myCodeFragmentMember) - : null; + final PsiType returnStatementType = getExpectedReturnType(); myHasReturnStatementOutput = myHasReturnStatement && returnStatementType != null && returnStatementType != PsiType.VOID; if (myGenerateConditionalExit && myOutputVariables.length == 1) { @@ -285,15 +284,7 @@ public class ExtractMethodProcessor implements MatchProvider { myNullConditionalCheck &= isNullInferred(myOutputVariables[0].getName(), false); } - if (insertNotNullCheckIfPossible() && myControlFlowWrapper.getOutputVariables(false).length == 0) { - myNotNullConditionalCheck = returnStatementType != null && returnStatementType != PsiType.VOID; - for (PsiStatement statement : myExitStatements) { - if (statement instanceof PsiReturnStatement) { - final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue(); - myNotNullConditionalCheck &= returnValue != null && !isNullInferred(returnValue.getText(), true); - } - } - } + myNotNullConditionalCheck = areAllExitPointsAreNotNull(returnStatementType); } if (!myHasReturnStatementOutput && checkOutputVariablesCount() && !myNullConditionalCheck && !myNotNullConditionalCheck) { @@ -343,6 +334,45 @@ public class ExtractMethodProcessor implements MatchProvider { return true; } + private PsiType getExpectedReturnType() { + return myCodeFragmentMember instanceof PsiMethod + ? ((PsiMethod)myCodeFragmentMember).getReturnType() + : myCodeFragmentMember instanceof PsiLambdaExpression + ? LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)myCodeFragmentMember) + : null; + } + + @Nullable + private PsiVariable getArtificialOutputVariable() { + if (myOutputVariables.length == 0) { + final VariablesProcessor processor = new VariablesProcessor(true) { + @Override + protected boolean check(PsiVariable var, ResolveState state) { + return isDeclaredInside(var); + } + }; + PsiScopesUtil.treeWalkUp(processor, myElements[myElements.length - 1], myCodeFragmentMember); + if (processor.size() == 1) { + return processor.getResult(0); + } + } + return null; + } + + private boolean areAllExitPointsAreNotNull(PsiType returnStatementType) { + if (insertNotNullCheckIfPossible() && myControlFlowWrapper.getOutputVariables(false).length == 0) { + boolean isNotNull = returnStatementType != null && returnStatementType != PsiType.VOID; + for (PsiStatement statement : myExitStatements) { + if (statement instanceof PsiReturnStatement) { + final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue(); + isNotNull &= returnValue != null && !isNullInferred(returnValue.getText(), true); + } + } + return isNotNull; + } + return false; + } + protected boolean insertNotNullCheckIfPossible() { return true; } @@ -498,7 +528,9 @@ public class ExtractMethodProcessor implements MatchProvider { final List variables = myInputVariables.getInputVariables(); myVariableDatum = variables.toArray(new VariableData[variables.size()]); myNullness = initNullness(); - return new ExtractMethodDialog(myProject, myTargetClass, myInputVariables, myReturnType, getTypeParameterList(), + myArtificialOutputVariable = PsiType.VOID.equals(myReturnType) ? getArtificialOutputVariable() : null; + final PsiType returnType = myArtificialOutputVariable != null ? myArtificialOutputVariable.getType() : myReturnType; + return new ExtractMethodDialog(myProject, myTargetClass, myInputVariables, returnType, getTypeParameterList(), getThrownExceptions(), isStatic(), isCanBeStatic(), myCanBeChainedConstructor, suggestInitialMethodName(), myRefactoringName, myHelpId, myNullness, myElements) { @@ -516,6 +548,10 @@ public class ExtractMethodProcessor implements MatchProvider { return ExtractMethodProcessor.this.isOutputVariable(var); } + protected boolean isVoidReturn() { + return myArtificialOutputVariable != null; + } + @Override protected void checkMethodConflicts(MultiMap conflicts) { super.checkMethodConflicts(conflicts); @@ -554,7 +590,19 @@ public class ExtractMethodProcessor implements MatchProvider { : PsiTreeUtil.findCommonParent(myElements); return CodeInsightUtil.findReferenceExpressions(scope, myOutputVariable); } - return PsiExpression.EMPTY_ARRAY; + final List filter = ContainerUtil.filter(myExitStatements, new Condition() { + @Override + public boolean value(PsiStatement statement) { + return statement instanceof PsiReturnStatement; + } + }); + final List map = ContainerUtil.map(filter, new Function() { + @Override + public PsiExpression fun(PsiStatement statement) { + return ((PsiReturnStatement) statement).getReturnValue(); + } + }); + return map.toArray(new PsiExpression[map.size()]); } private Nullness initNullness() { @@ -639,7 +687,17 @@ public class ExtractMethodProcessor implements MatchProvider { } @TestOnly - public void testPrepare(PsiType returnType) { + public void testPrepare(PsiType returnType, boolean makeStatic) throws PrepareFailedException{ + if (makeStatic) { + if (!isCanBeStatic()) { + throw new PrepareFailedException("Failed to make static", myElements[0]); + } + myInputVariables.setPassFields(true); + myStatic = true; + } + if (PsiType.VOID.equals(myReturnType)) { + myArtificialOutputVariable = getArtificialOutputVariable(); + } testPrepare(); if (returnType != null) { myReturnType = returnType; @@ -709,7 +767,7 @@ public class ExtractMethodProcessor implements MatchProvider { } } - private void initDuplicates() { + private DuplicatesFinder initDuplicates() { List elements = new ArrayList(); for (PsiElement element : myElements) { if (!(element instanceof PsiWhiteSpace || element instanceof PsiComment)) { @@ -718,18 +776,21 @@ public class ExtractMethodProcessor implements MatchProvider { } if (myExpression != null) { - myDuplicatesFinder = new DuplicatesFinder(PsiUtilCore.toPsiElementArray(elements), myInputVariables.copy(), + DuplicatesFinder finder = new DuplicatesFinder(PsiUtilCore.toPsiElementArray(elements), myInputVariables.copy(), new ArrayList()); - myDuplicates = myDuplicatesFinder.findDuplicates(myTargetClass); + myDuplicates = finder.findDuplicates(myTargetClass); + return finder; } else if (elements.size() > 0){ - myDuplicatesFinder = new DuplicatesFinder(PsiUtilCore.toPsiElementArray(elements), myInputVariables.copy(), + DuplicatesFinder myDuplicatesFinder = new DuplicatesFinder(PsiUtilCore.toPsiElementArray(elements), myInputVariables.copy(), myOutputVariable != null ? new VariableReturnValue(myOutputVariable) : null, Arrays.asList(myOutputVariables)); myDuplicates = myDuplicatesFinder.findDuplicates(myTargetClass); + return myDuplicatesFinder; } else { myDuplicates = new ArrayList(); } + return null; } public void doExtract() throws IncorrectOperationException { @@ -787,7 +848,7 @@ public class ExtractMethodProcessor implements MatchProvider { CodeStyleManager.getInstance(myProject).reformat(ifStatement); } else if (myNotNullConditionalCheck) { - String varName = myOutputVariable.getName(); + String varName = myOutputVariable != null ? myOutputVariable.getName() : "x"; varName = declareVariableAtMethodCallLocation(varName, myReturnType instanceof PsiPrimitiveType ? ((PsiPrimitiveType)myReturnType).getBoxedType(myCodeFragmentMember) : myReturnType); addToMethodCallLocation(myElementFactory.createStatementFromText("if (" + varName + " != null) return " + varName + ";", null)); } @@ -818,9 +879,14 @@ public class ExtractMethodProcessor implements MatchProvider { myMethodCall = (PsiMethodCallExpression)((PsiReturnStatement)statement).getReturnValue().replace(myMethodCall); } else { - PsiStatement statement = myElementFactory.createStatementFromText("x();", null); - statement = (PsiStatement)addToMethodCallLocation(statement); - myMethodCall = (PsiMethodCallExpression)((PsiExpressionStatement)statement).getExpression().replace(myMethodCall); + if (myArtificialOutputVariable != null && myReturnType != PsiType.VOID) { + declareVariableAtMethodCallLocation(myArtificialOutputVariable.getName()); + } + else { + PsiStatement statement = myElementFactory.createStatementFromText("x();", null); + statement = (PsiStatement)addToMethodCallLocation(statement); + myMethodCall = (PsiMethodCallExpression)((PsiExpressionStatement)statement).getExpression().replace(myMethodCall); + } } if (myHasReturnStatement && !myHasReturnStatementOutput && !hasNormalExit()) { PsiStatement statement = myElementFactory.createStatementFromText("return;", null); @@ -980,6 +1046,9 @@ public class ExtractMethodProcessor implements MatchProvider { } } } + else if (myArtificialOutputVariable != null && !PsiType.VOID.equals(myReturnType)) { + body.add(myElementFactory.createStatementFromText("return " + myArtificialOutputVariable.getName() + ";", null)); + } return exitStatementCopy; } @@ -1012,7 +1081,9 @@ public class ExtractMethodProcessor implements MatchProvider { statement = (PsiDeclarationStatement)addToMethodCallLocation(statement); PsiVariable var = (PsiVariable)statement.getDeclaredElements()[0]; myMethodCall = (PsiMethodCallExpression)var.getInitializer(); - var.getModifierList().replace(myOutputVariable.getModifierList()); + if (myOutputVariable != null) { + var.getModifierList().replace(myOutputVariable.getModifierList()); + } return name; } @@ -1462,8 +1533,21 @@ public class ExtractMethodProcessor implements MatchProvider { private boolean applyChosenClassAndExtract(List inputVariables, @Nullable Pass extractPass) throws PrepareFailedException { myStatic = shouldBeStatic(); + final Set fields = new LinkedHashSet(); if (!PsiUtil.isLocalOrAnonymousClass(myTargetClass) && (myTargetClass.getContainingClass() == null || myTargetClass.hasModifierProperty(PsiModifier.STATIC))) { - ElementNeedsThis needsThis = new ElementNeedsThis(myTargetClass); + ElementNeedsThis needsThis = new ElementNeedsThis(myTargetClass) { + @Override + protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { + if (classMember instanceof PsiField && !classMember.hasModifierProperty(PsiModifier.STATIC)) { + final PsiExpression expression = PsiTreeUtil.getParentOfType(classMemberReference, PsiExpression.class, false); + if (expression == null || !PsiUtil.isAccessedForWriting(expression)) { + fields.add((PsiField)classMember); + return; + } + } + super.visitClassMemberReferenceElement(classMember, classMemberReference); + } + }; for (int i = 0; i < myElements.length && !needsThis.usesMembers(); i++) { PsiElement element = myElements[i]; element.accept(needsThis); @@ -1475,6 +1559,7 @@ public class ExtractMethodProcessor implements MatchProvider { } myInputVariables = new InputVariables(inputVariables, myProject, new LocalSearchScope(myElements), true); + myInputVariables.setUsedInstanceFields(fields); if (!checkExitPoints()){ return false; @@ -1561,12 +1646,12 @@ public class ExtractMethodProcessor implements MatchProvider { } public boolean hasDuplicates(Set files) { - initDuplicates(); + final DuplicatesFinder finder = initDuplicates(); if (hasDuplicates()) return true; final PsiManager psiManager = PsiManager.getInstance(myProject); for (VirtualFile file : files) { - if (!myDuplicatesFinder.findDuplicates(psiManager.findFile(file)).isEmpty()) return true; + if (!finder.findDuplicates(psiManager.findFile(file)).isEmpty()) return true; } return false; } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java index 28da2a95e3b6..fb356601ae45 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java @@ -118,7 +118,10 @@ public class ReassignVariableUtil { }; PsiElement scope = declaration; while (scope != null) { - if (scope instanceof PsiFile || scope instanceof PsiMethod || scope instanceof PsiClassInitializer) break; + if (scope instanceof PsiFile || + scope instanceof PsiMethod || + scope instanceof PsiLambdaExpression || + scope instanceof PsiClassInitializer) break; scope = scope.getParent(); } if (scope == null) return proc; diff --git a/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java b/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java index 6d0f184056df..b43a5e7f240c 100644 --- a/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java +++ b/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java @@ -205,7 +205,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { } } - private PsiType[] getTypesForAll(final boolean areTypesDirected) { + protected PsiType[] getTypesForAll(final boolean areTypesDirected) { final ArrayList expectedTypesFromAll = new ArrayList(); for (PsiExpression occurrence : myOccurrences) { final ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(occurrence, false, myOccurrenceClassProvider, isUsedAfter()); 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 59f0a010d4d8..403043d38952 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java @@ -24,7 +24,6 @@ import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizableStringList; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.*; -import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.containers.ContainerUtil; import org.jdom.Element; @@ -168,30 +167,16 @@ public class NullableNotNullManager implements PersistentStateComponent myDefaultNotNull = defaultNotNull; } - private static boolean skipAnnotation(@NotNull PsiAnnotation annotation, @NotNull PsiModifierListOwner owner) { - return owner instanceof PsiMethod && - PsiUtil.canBeOverriden((PsiMethod)owner) && - AnnotationUtil.isInferredAnnotation(annotation) && - AnnotationUtil.NOT_NULL.equals(annotation.getQualifiedName()); - } - @Nullable private PsiAnnotation findNullabilityAnnotation(@NotNull PsiModifierListOwner owner, boolean checkBases, boolean nullable) { Set qNames = ContainerUtil.newHashSet(nullable ? getNullables() : getNotNulls()); - PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, qNames); - if (annotation != null && !skipAnnotation(annotation, owner)) { + PsiAnnotation annotation = checkBases && (owner instanceof PsiClass || owner instanceof PsiMethod) + ? AnnotationUtil.findAnnotationInHierarchy(owner, qNames) + : AnnotationUtil.findAnnotation(owner, qNames); + if (annotation != null) { return annotation; } - if (checkBases && owner instanceof PsiMethod) { - for (PsiModifierListOwner superOwner : AnnotationUtil.getSuperAnnotationOwners(owner)) { - annotation = AnnotationUtil.findAnnotation(superOwner, qNames); - if (annotation != null && !skipAnnotation(annotation, superOwner)) { - return annotation; - } - } - } - PsiType type = getOwnerType(owner); if (type == null || TypeConversionUtil.isPrimitiveAndNotNull(type)) return null; @@ -317,7 +302,6 @@ public class NullableNotNullManager implements PersistentStateComponent } try { - //noinspection deprecation DefaultJDOMExternalizer.writeExternal(this, component); } catch (WriteExternalException e) { @@ -329,7 +313,6 @@ public class NullableNotNullManager implements PersistentStateComponent @Override public void loadState(Element state) { try { - //noinspection deprecation DefaultJDOMExternalizer.readExternal(this, state); if (myNullables.isEmpty()) { Collections.addAll(myNullables, DEFAULT_NULLABLES); 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 2369bf3ccdcb..3c6e04fb1ad2 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 @@ -514,7 +514,8 @@ public final class PsiUtil extends PsiUtilCore { PsiType lastParmType = getParameterType(lastParameter, languageLevel, substitutorForMethod); if (!(lastParmType instanceof PsiArrayType)) return ApplicabilityLevel.NOT_APPLICABLE; lastParmType = ((PsiArrayType)lastParmType).getComponentType(); - if (lastParmType instanceof PsiCapturedWildcardType && !JavaVersionService.getInstance().isAtLeast(lastParameter, JavaSdkVersion.JDK_1_8)) { + if (lastParmType instanceof PsiCapturedWildcardType && + !JavaVersionService.getInstance().isAtLeast(((PsiCapturedWildcardType)lastParmType).getContext(), JavaSdkVersion.JDK_1_8)) { lastParmType = ((PsiCapturedWildcardType)lastParmType).getWildcard(); } for (int i = parms.length - 1; i < args.length; i++) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java index 7cee51c2d914..a93170650aa8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java @@ -240,7 +240,7 @@ public class PsiReferenceExpressionImpl extends PsiReferenceExpressionBase imple private JavaResolveResult[] resolve(IElementType parentType, @NotNull PsiFile containingFile) { if (parentType == JavaElementType.REFERENCE_EXPRESSION) { JavaResolveResult[] result = resolveToVariable(containingFile); - if (result.length > 0) { + if (result.length == 1 && result[0].isAccessible()) { return result; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/PrivateFieldInSuperClass.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/PrivateFieldInSuperClass.java new file mode 100644 index 000000000000..772288631436 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/PrivateFieldInSuperClass.java @@ -0,0 +1,11 @@ +class C { + private int id; +} + +class A extends C { + { + id.MyObject.fromInt(1); + + id.MyObject o; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/afterLambdaException.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/afterLambdaException.java new file mode 100644 index 000000000000..9d6d0638c7af --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/afterLambdaException.java @@ -0,0 +1,14 @@ +// "Create Local Variable 'v'" "true" +public class A { + void foo() { + L l = () -> { + MyException v; + throw v + } + } + + interface L { + void g() throws MyException; + } + class MyException extends Exception {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/beforeLambdaException.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/beforeLambdaException.java new file mode 100644 index 000000000000..f9d8ceb5cc95 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/beforeLambdaException.java @@ -0,0 +1,13 @@ +// "Create Local Variable 'v'" "true" +public class A { + void foo() { + L l = () -> { + throw v + } + } + + interface L { + void g() throws MyException; + } + class MyException extends Exception {} +} diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/annotations.xml index 3785aeaa7972..434f79c0dac6 100644 --- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/annotations.xml +++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/annotations.xml @@ -2346,11 +2346,6 @@ - - - - - diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/annotations.xml index 856854638892..209d666d1f83 100644 --- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/annotations.xml +++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/annotations.xml @@ -3834,18 +3834,12 @@ - - - - - + + - - - - + + - diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/CompileTimeConstant.java b/java/java-tests/testData/inspection/dataFlow/fixture/CompileTimeConstant.java new file mode 100644 index 000000000000..401df4ccf61c --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/CompileTimeConstant.java @@ -0,0 +1,14 @@ +class Fun { + public static final boolean isDebug = true; + + void foo() { + if (isDebug) { + System.out.println(); + } + } + void fooNegated() { + if (!isDebug) { + System.out.println(); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/CantPassFieldAsParameter.java b/java/java-tests/testData/refactoring/extractMethod/CantPassFieldAsParameter.java new file mode 100644 index 000000000000..7eb85c4ab5c5 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/CantPassFieldAsParameter.java @@ -0,0 +1,6 @@ +class X { + private int myI; + void foo() { + int i = myI++; + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/ExitPoints4Nullable.java b/java/java-tests/testData/refactoring/extractMethod/ExitPoints4Nullable.java new file mode 100644 index 000000000000..577dc8b66ae7 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/ExitPoints4Nullable.java @@ -0,0 +1,12 @@ +class Test { + Integer method() { + try { + if(cond1) return 0; + else if(cond2) return null; + System.out.println("Text"); + } finally { + doSomething(); + } + return 12; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/ExitPoints4_after.java b/java/java-tests/testData/refactoring/extractMethod/ExitPoints4_after.java new file mode 100644 index 000000000000..6d81150b09c3 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/ExitPoints4_after.java @@ -0,0 +1,21 @@ +import org.jetbrains.annotations.Nullable; + +class Test { + int method() { + Integer x = newMethod(); + if (x != null) return x; + return 12; + } + + @Nullable + private Integer newMethod() { + try { + if(cond1) return 0; + else if(cond2) return 1; + System.out.println("Text"); + } finally { + doSomething(); + } + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable.java b/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable.java new file mode 100644 index 000000000000..894c81cfd965 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable.java @@ -0,0 +1,5 @@ +class X { + void foo() { + int x = 0; + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable_after.java b/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable_after.java new file mode 100644 index 000000000000..bd8821fd26b1 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable_after.java @@ -0,0 +1,10 @@ +class X { + void foo() { + int x = newMethod(); + } + + private int newMethod() { + int x = 0; + return x; + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment.java b/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment.java new file mode 100644 index 000000000000..6f57cbf63da3 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment.java @@ -0,0 +1,7 @@ +class X { + void foo() { + int x = 0; + int y = 42; + + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment_after.java b/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment_after.java new file mode 100644 index 000000000000..86dabe6e8d91 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment_after.java @@ -0,0 +1,11 @@ +class X { + void foo() { + newMethod(); + + } + + private int newMethod() { + int x = 0; + int y = 42; + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/PassFieldAsParameterAndMakeStatic.java b/java/java-tests/testData/refactoring/extractMethod/PassFieldAsParameterAndMakeStatic.java new file mode 100644 index 000000000000..f7ad526a2faa --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/PassFieldAsParameterAndMakeStatic.java @@ -0,0 +1,6 @@ +class X { + private int myI; + void foo() { + int i = myI; + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/PassFieldAsParameterAndMakeStatic_after.java b/java/java-tests/testData/refactoring/extractMethod/PassFieldAsParameterAndMakeStatic_after.java new file mode 100644 index 000000000000..1ba4ed63953d --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/PassFieldAsParameterAndMakeStatic_after.java @@ -0,0 +1,10 @@ +class X { + private int myI; + void foo() { + newMethod(myI); + } + + private static void newMethod(int myI) { + int i = myI; + } +} diff --git a/java/java-tests/testData/refactoring/suggestedTypes/OutputUsedInReturn.java b/java/java-tests/testData/refactoring/suggestedTypes/OutputUsedInReturn.java new file mode 100644 index 000000000000..c70305ba66ae --- /dev/null +++ b/java/java-tests/testData/refactoring/suggestedTypes/OutputUsedInReturn.java @@ -0,0 +1,13 @@ +class Test { + String foo(boolean b) { + + if (b) { + return "a"; + } + if (!b) { + return "b"; + } + + return "42"; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java index aaf4ae106d31..832290d5d733 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java @@ -391,6 +391,7 @@ public class LightAdvHighlightingTest extends LightDaemonAnalyzerTestCase { public void testIDEA18343() { doTest(false, false); } public void testNewExpressionClass() { doTest(false, false); } public void testInnerClassObjectLiteralFromSuperExpression() { doTest(false, false); } + public void testPrivateFieldInSuperClass() { doTest(false, false); } public void testNoEnclosingInstanceWhenStaticNestedInheritsFromContainingClass() throws Exception { doTest(false, false); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/completion/TemplatesCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/completion/TemplatesCompletionTest.java index 277a15b5b53a..1c913ff5dd54 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/completion/TemplatesCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/completion/TemplatesCompletionTest.java @@ -126,7 +126,7 @@ public class TemplatesCompletionTest extends CompletionAutoPopupTestCase { doAutoPopupTest("instanceof", null); } - public void testDoNotAutoCompleteCompletionElementIfTemplateUnique() { + public void testDoNotAutoCompleteCompletionElementIfTemplateUnique() { LiveTemplateCompletionContributor.ourShowTemplatesInTests = true; configureByFile(); myFixture.completeBasic(); diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy b/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy index 13ba25910061..2218671ada90 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy @@ -239,6 +239,28 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase { assert c == [] } + public void "test return boxed integer"() { + def c = inferContracts(""" + static Object test1(Object o1) { + return o1 == null ? 1 : smth(); + } + + static native Object smth() + """) + assert c == ['null -> !null'] + } + + public void "test return boxed boolean"() { + def c = inferContracts(""" + static Object test1(Object o1) { + return o1 == null ? false : smth(); + } + + static native Object smth() + """) + assert c == ['null -> !null'] + } + public void "test boolean autoboxing in delegation"() { def c = inferContracts(""" static Boolean test04(String s) { @@ -391,6 +413,15 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase { assert c == ['null -> null'] } + public void "test compare with string literal"() { + def c = inferContracts(""" + String cast(String s) { + return s == "a" ? "b" : null; + } + """) + assert c == [] + } + public void "test return after if without else"() { def c = inferContracts(""" public static boolean isBlank(String s) { diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index 4276d58e24c7..90e7d127b8b5 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -184,6 +184,8 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { public void testUnknownFloatMayBeNaN() { doTest(); } public void testFloatEquality() { doTest(); } public void testLastConstantConditionInAnd() { doTest(); } + + public void testCompileTimeConstant() { doTest(); } public void testTransientFinalField() { doTest(); } public void testRememberLocalTransientFieldState() { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy b/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy index 3b60d9549375..c6b6bfd65149 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy @@ -42,6 +42,17 @@ abstract class NullityInferenceFromSourceTestCase extends LightCodeInsightFixtur assert inferNullity(parse('String foo() { return bar(); }; String bar() { return "z"; }; ')) == NOT_NULL } + void "test same delegate method invoked twice"() { + assert inferNullity(parse(''' +String foo() { + if (equals(2)) return bar(); + if (equals(3)) return bar(); + return "abc"; +} +String bar() { return "z"; } +''')) == NOT_NULL + } + void "test if branch returns null"() { assert inferNullity(parse('String bar() { if (equals(2)) return null; return "a"; }; ')) == NULLABLE } @@ -50,9 +61,21 @@ abstract class NullityInferenceFromSourceTestCase extends LightCodeInsightFixtur assert inferNullity(parse('String foo() { return bar(); }; String bar() { if (equals(2)) return null; return "a"; }; ')) == UNKNOWN } + void "test return boxed boolean constant"() { + assert inferNullity(parse('Object foo() { return true; }')) == NOT_NULL + } + + void "test return boxed boolean value"() { + assert inferNullity(parse('Object foo(Object o) { return o == null; }')) == NOT_NULL + } + + void "test return boxed integer"() { + assert inferNullity(parse('Object foo() { return 1; }')) == NOT_NULL + } + protected abstract Nullness inferNullity(PsiMethod method) - private PsiMethod parse(String method) { + protected PsiMethod parse(String method) { return myFixture.addClass("final class Foo { $method }").methods[0] } @@ -60,6 +83,10 @@ abstract class NullityInferenceFromSourceTestCase extends LightCodeInsightFixtur Nullness inferNullity(PsiMethod method) { return NullableNotNullManager.isNotNull(method) ? NOT_NULL : NullableNotNullManager.isNullable(method) ? NULLABLE : UNKNOWN } + + void "test skip when errors"() { + assert inferNullity(parse('String foo() { if(); return 2; } ')) == UNKNOWN + } } static class DfaInferenceTest extends NullityInferenceFromSourceTestCase { diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java index e55cf30c6a69..8a7340c76093 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java @@ -17,7 +17,6 @@ package com.intellij.codeInspection.bytecodeAnalysis; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.ExternalAnnotationsManager; -import com.intellij.codeInsight.InferredAnnotationsManager; import com.intellij.codeInsight.daemon.GutterMark; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.projectRoots.Sdk; @@ -257,7 +256,7 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC @Nullable private PsiAnnotation findInferredAnnotation(PsiModifierListOwner owner, String fqn) { - return InferredAnnotationsManager.getInstance(myModule.getProject()).findInferredAnnotation(owner, fqn); + return ProjectBytecodeAnalysis.getInstance(getProject()).findInferredAnnotation(owner, fqn); } @Nullable 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 b0ff724c03d3..2c684b72c4a6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java @@ -16,7 +16,6 @@ package com.intellij.codeInspection.bytecodeAnalysis; import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.codeInsight.InferredAnnotationsManager; import com.intellij.codeInspection.bytecodeAnalysis.asm.LeakingParameters; import com.intellij.codeInspection.bytecodeAnalysis.data.*; import com.intellij.openapi.util.io.FileUtil; @@ -48,7 +47,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase { public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName(); private final String myClassesProjectRelativePath = "/classes/" + Test01.class.getPackage().getName().replace('.', '/'); private JavaPsiFacade myJavaPsiFacade; - private InferredAnnotationsManager myInferredAnnotationsManager; + private ProjectBytecodeAnalysis myBytecodeAnalysisService; private MessageDigest myMessageDigest; @@ -56,7 +55,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase { protected void setUp() throws Exception { super.setUp(); myJavaPsiFacade = JavaPsiFacade.getInstance(myModule.getProject()); - myInferredAnnotationsManager = InferredAnnotationsManager.getInstance(myModule.getProject()); + myBytecodeAnalysisService = ProjectBytecodeAnalysis.getInstance(myModule.getProject()); myMessageDigest = MessageDigest.getInstance("MD5"); setUpDataClasses(); } @@ -131,7 +130,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase { params: for (int i = 0; i < annotations.length; i++) { Annotation[] parameterAnnotations = annotations[i]; PsiParameter psiParameter = psiMethod.getParameterList().getParameters()[i]; - PsiAnnotation inferredAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiParameter, AnnotationUtil.NOT_NULL); + PsiAnnotation inferredAnnotation = myBytecodeAnalysisService.findInferredAnnotation(psiParameter, AnnotationUtil.NOT_NULL); for (Annotation parameterAnnotation : parameterAnnotations) { if (parameterAnnotation.annotationType() == ExpectNotNull.class) { assertNotNull(javaMethod.toString() + " " + i, inferredAnnotation); @@ -143,13 +142,13 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase { // not-null result ExpectNotNull expectedAnnotation = javaMethod.getAnnotation(ExpectNotNull.class); - PsiAnnotation actualAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, AnnotationUtil.NOT_NULL); + PsiAnnotation actualAnnotation = myBytecodeAnalysisService.findInferredAnnotation(psiMethod, AnnotationUtil.NOT_NULL); assertEquals(javaMethod.toString(), expectedAnnotation == null, actualAnnotation == null); // contracts ExpectContract expectedContract = javaMethod.getAnnotation(ExpectContract.class); - PsiAnnotation actualContract = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, ORG_JETBRAINS_ANNOTATIONS_CONTRACT); + PsiAnnotation actualContract = myBytecodeAnalysisService.findInferredAnnotation(psiMethod, ORG_JETBRAINS_ANNOTATIONS_CONTRACT); String expectedText = expectedContract == null ? "null" : expectedContract.toString(); String inferredText = actualContract == null ? "null" : actualContract.getText(); diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy index 64492f94d62a..9f4de6950d72 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy @@ -252,7 +252,8 @@ public class IndexTest extends JavaCodeInsightFixtureTestCase { ((VirtualFileSystemEntry)vFile).setModificationStamp(0); // as unchanged file final Document document = FileDocumentManager.getInstance().getDocument(vFile); - assertTrue(document != null && document.getModificationStamp() == 0); + assertTrue(document != null); + assert document.getModificationStamp() == 0; assertNotNull(findClass("Foo")); WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() { diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index b6a705f56ec5..97d58a12ae6d 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -58,6 +58,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { } public void testExitPoints4() throws Exception { + doTest(); + } + + public void testExitPoints4Nullable() throws Exception { doExitPointsTest(false); } @@ -625,6 +629,28 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doTestReturnTypeChanged(PsiType.getJavaLangObject(getPsiManager(), GlobalSearchScope.allScope(getProject()))); } + public void testMakeVoidMethodReturnVariable() throws Exception { + doTestReturnTypeChanged(PsiType.INT); + } + + public void testMultipleVarsInMethodNoReturnStatementAndAssignment() throws Exception { + //return type should not be suggested but still + doTestReturnTypeChanged(PsiType.INT); + } + + public void testPassFieldAsParameterAndMakeStatic() throws Exception { + doTestPassFieldsAsParams(); + } + + public void testCantPassFieldAsParameter() throws Exception { + try { + doTestPassFieldsAsParams(); + fail("Field was modified inside. Make static should be disabled"); + } + catch (PrepareFailedException ignore) { + } + } + private void doTestDisabledParam() throws PrepareFailedException { final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); settings.ELSE_ON_NEW_LINE = true; @@ -640,7 +666,17 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { settings.ELSE_ON_NEW_LINE = true; settings.CATCH_ON_NEW_LINE = myCatchOnNewLine; configureByFile(BASE_PATH + getTestName(false) + ".java"); - boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, type); + boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, type, false); + assertTrue(success); + checkResultByFile(BASE_PATH + getTestName(false) + "_after.java"); + } + + private void doTestPassFieldsAsParams() throws PrepareFailedException { + final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); + settings.ELSE_ON_NEW_LINE = true; + settings.CATCH_ON_NEW_LINE = myCatchOnNewLine; + configureByFile(BASE_PATH + getTestName(false) + ".java"); + boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, null, true); assertTrue(success); checkResultByFile(BASE_PATH + getTestName(false) + "_after.java"); } @@ -700,7 +736,7 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { final boolean extractChainedConstructor, int... disabledParams) throws PrepareFailedException, IncorrectOperationException { - return performExtractMethod(doRefactor, replaceAllDuplicates, editor, file, project, extractChainedConstructor, null, disabledParams); + return performExtractMethod(doRefactor, replaceAllDuplicates, editor, file, project, extractChainedConstructor, null, false, disabledParams); } public static boolean performExtractMethod(boolean doRefactor, @@ -710,6 +746,7 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { Project project, final boolean extractChainedConstructor, PsiType returnType, + boolean makeStatic, int... disabledParams) throws PrepareFailedException, IncorrectOperationException { int startOffset = editor.getSelectionModel().getSelectionStart(); @@ -741,7 +778,7 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { } if (doRefactor) { - processor.testPrepare(returnType); + processor.testPrepare(returnType, makeStatic); processor.testNullness(); if (disabledParams != null) { for (int param : disabledParams) { diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ReplaceMethodDuplicatesTestSuite.java b/java/java-tests/testSrc/com/intellij/refactoring/ReplaceMethodDuplicatesTestSuite.java index 587184dd50a4..ebeb25624c31 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ReplaceMethodDuplicatesTestSuite.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ReplaceMethodDuplicatesTestSuite.java @@ -20,6 +20,7 @@ public class ReplaceMethodDuplicatesTestSuite { testSuite.addTestSuite(FindMethodDuplicatesMiscTest.class); testSuite.addTestSuite(FindMethodDuplicatesTest.class); testSuite.addTestSuite(SuggestedParamTypesTest.class); + testSuite.addTestSuite(SuggestedReturnTypesTest.class); return testSuite; } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/SuggestedReturnTypesTest.java b/java/java-tests/testSrc/com/intellij/refactoring/SuggestedReturnTypesTest.java index 20a1ca5b9ac5..136f3c485a22 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/SuggestedReturnTypesTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/SuggestedReturnTypesTest.java @@ -61,6 +61,10 @@ public class SuggestedReturnTypesTest extends LightCodeInsightTestCase { doTest("Integer", "int"); } + public void testOutputUsedInReturn() throws Exception { + doTest("String"); + } + private void doTest(String... types) throws Exception { configureByFile(BASE_PATH + getTestName(false) + ".java"); diff --git a/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java b/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java index 8c21f16eb6f7..45acbb86108c 100644 --- a/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java +++ b/platform/analysis-api/src/com/intellij/codeHighlighting/HighlightDisplayLevel.java @@ -115,11 +115,11 @@ public class HighlightDisplayLevel { @NotNull public static Icon createIconByMask(final Color renderColor) { - return new MyColorIcon(EMPTY_ICON_DIM, renderColor); + return new TheColorIcon(EMPTY_ICON_DIM, renderColor); } - private static class MyColorIcon extends ColorIcon implements ColoredIcon { - public MyColorIcon(int size, @NotNull Color color) { + public static class TheColorIcon extends ColorIcon implements ColoredIcon { + public TheColorIcon(int size, @NotNull Color color) { super(size, color); } diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java index f0aca8b5d272..496c9ca48f74 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java @@ -93,7 +93,9 @@ public class SeverityRegistrar implements JDOMExternalizable, Comparator myDocumentSet = new WeakList(); + private final WeakList myDocumentSet = new WeakList(); private volatile boolean myDisposed; public static DocumentMarkupModelManager getInstance(Project project) { @@ -46,7 +47,7 @@ public class DocumentMarkupModelManager extends AbstractProjectComponent { }); } - public void registerDocument(DocumentImpl document) { + public void registerDocument(Document document) { LOG.assertTrue(!myDisposed); myDocumentSet.add(document); } @@ -58,7 +59,7 @@ public class DocumentMarkupModelManager extends AbstractProjectComponent { private void cleanupProjectMarkups() { if (!myDisposed) { myDisposed = true; - for (DocumentImpl document : myDocumentSet.toStrongList()) { + for (Document document : myDocumentSet.toStrongList()) { DocumentMarkupModel.removeMarkupModel(document, myProject); } } diff --git a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/EditScopesDialog.java b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/EditScopesDialog.java index bb5d6bb2efe6..236c6fd717fa 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/EditScopesDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/EditScopesDialog.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. @@ -58,7 +58,7 @@ public class EditScopesDialog extends SettingsDialog { } @Override - protected void doOKAction() { + public void doOKAction() { Object selectedObject = myConfigurable.getSelectedObject(); mySelectedScope = selectedObject instanceof NamedScope ? (NamedScope)selectedObject : null; diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java index 5ef283edb039..cb88754cce73 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java @@ -29,6 +29,7 @@ import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.profile.codeInspection.SeverityProvider; +import com.intellij.profile.codeInspection.ui.table.SeverityRenderer; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -65,7 +66,7 @@ public abstract class LevelChooserAction extends ComboBoxAction implements DumbA group.addSeparator(); group.add(new DumbAwareAction("Edit severities...") { @Override - public void actionPerformed(final AnActionEvent e) { + public void actionPerformed(@NotNull final AnActionEvent e) { final SeverityEditorDialog dlg = new SeverityEditorDialog(anchor, myChosen, mySeverityRegistrar); if (dlg.showAndGet()) { final HighlightInfoType type = dlg.getSelectedType(); @@ -98,7 +99,7 @@ public abstract class LevelChooserAction extends ComboBoxAction implements DumbA myChosen = severity; final Presentation templatePresentation = getTemplatePresentation(); templatePresentation.setText(SingleInspectionProfilePanel.renderSeverity(severity)); - templatePresentation.setIcon(HighlightDisplayLevel.find(severity).getIcon()); + templatePresentation.setIcon(SeverityRenderer.getIcon(HighlightDisplayLevel.find(severity))); } private class HighlightSeverityAction extends DumbAwareAction { @@ -112,11 +113,11 @@ public abstract class LevelChooserAction extends ComboBoxAction implements DumbA mySeverity = severity; final Presentation presentation = getTemplatePresentation(); presentation.setText(SingleInspectionProfilePanel.renderSeverity(severity)); - presentation.setIcon(HighlightDisplayLevel.find(severity).getIcon()); + presentation.setIcon(SeverityRenderer.getIcon(HighlightDisplayLevel.find(severity))); } @Override - public void actionPerformed(final AnActionEvent e) { + public void actionPerformed(@NotNull final AnActionEvent e) { final HighlightSeverity severity = getSeverity(); setChosen(severity); onChosen(severity); diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java index b5b7de27fddc..2b06dbd9cdbb 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java @@ -548,12 +548,12 @@ public class SingleInspectionProfilePanel extends JPanel { actions.add(new DumbAwareAction("Reset to Empty", "Reset to empty", AllIcons.Actions.Reset_to_empty){ @Override - public void update(AnActionEvent e) { + public void update(@NotNull AnActionEvent e) { e.getPresentation().setEnabled(mySelectedProfile != null && mySelectedProfile.isExecutable(myProjectProfileManager.getProject())); } @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { mySelectedProfile.resetToEmpty(e.getProject()); loadDescriptorsConfigs(false); postProcessModification(); @@ -753,7 +753,7 @@ public class SingleInspectionProfilePanel extends JPanel { final HighlightDisplayLevel level = HighlightDisplayLevel.find(severity); group.add(new AnAction(renderSeverity(severity), renderSeverity(severity), level.getIcon()) { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { setNewHighlightingLevel(level); } diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java index 1ef7b4d0de84..52a66754c21e 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java @@ -25,6 +25,7 @@ import com.intellij.profile.codeInspection.ui.LevelChooserAction; import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.ColorIcon; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -58,6 +59,13 @@ public class SeverityRenderer extends ComboBoxTableRenderer { }), onClose); } + public static Icon getIcon(@NotNull HighlightDisplayLevel level) { + Icon icon = level.getIcon(); + return icon instanceof HighlightDisplayLevel.ColoredIcon + ? new ColorIcon(icon.getIconWidth(), ((HighlightDisplayLevel.ColoredIcon)icon).getColor()) + : icon; + } + @Override protected void customizeComponent(SeverityState value, JTable table, boolean isSelected) { super.customizeComponent(value, table, isSelected); @@ -73,7 +81,7 @@ public class SeverityRenderer extends ComboBoxTableRenderer { @Override protected Icon getIconFor(@NotNull final SeverityState value) { - return HighlightDisplayLevel.find(value.getSeverity()).getIcon(); + return getIcon(HighlightDisplayLevel.find(value.getSeverity())); } @Override diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubTreeLoaderImpl.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubTreeLoaderImpl.java index eefbba7e512b..e3e4616ee5de 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubTreeLoaderImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubTreeLoaderImpl.java @@ -167,4 +167,9 @@ public class StubTreeLoaderImpl extends StubTreeLoader { public boolean canHaveStub(VirtualFile file) { return StubUpdatingIndex.canHaveStub(file); } + + @Override + public String getIndexingStampDebugInfo(VirtualFile file) { + return StubUpdatingIndex.getIndexingStampInfo(file); + } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java index a6b7e42bed02..f06ffa405197 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java @@ -51,6 +51,7 @@ import com.intellij.util.PlatformIcons; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.table.JBListTable; import com.intellij.util.ui.table.JBTableRowEditor; +import com.intellij.util.ui.table.JBTableRowRenderer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -458,37 +459,7 @@ public abstract class ChangeSignatureDialogBase items = myParametersTable.getItems(); - return getRowPresentation(items.get(row), selected, focused); - } - - @Override - protected boolean isRowEmpty(int row) { - final List items = myParametersTable.getItems(); - return isEmptyRow(items.get(row)); - } - - @Override - protected JBTableRowEditor getRowEditor(final int row) { - final List items = myParametersTable.getItems(); - JBTableRowEditor editor = getTableEditor(myParametersList.getTable(), items.get(row)); - LOG.assertTrue(editor != null); - editor.addDocumentListener(new JBTableRowEditor.RowDocumentListener() { - @Override - public void documentChanged(DocumentEvent e, int column) { - if (myParametersTableModel.getColumnClass(column).equals(String.class)) { - myParametersTableModel.setValueAtWithoutUpdate(e.getDocument().getText(), row, column); - } - - updateSignature(); - } - }); - return editor; - } - }; + myParametersList = createParametersListTable(); final JPanel buttonsPanel = ToolbarDecorator.createDecorator(myParametersList.getTable()) .addExtraAction(myPropagateParamChangesButton) .createPanel(); @@ -512,15 +483,56 @@ public abstract class ChangeSignatureDialogBase item) { + JBTableRowEditor editor = ChangeSignatureDialogBase.this.getTableEditor(getTable(), item); + LOG.assertTrue(editor != null); + return editor; + } + + @Override + protected boolean isRowEmpty(int row) { + return ChangeSignatureDialogBase.this.isEmptyRow(getRowItem(row)); + } + }; + } + + /** + * @deprecated override {@link #createParametersListTable} instead. + */ + @Deprecated @Nullable protected JBTableRowEditor getTableEditor(JTable table, ParameterTableModelItemBase item) { return null; } + /** + * @deprecated override {@link #createParametersListTable} instead. + */ + @Deprecated protected boolean isEmptyRow(ParameterTableModelItemBase row) { return false; } + /** + * @deprecated override {@link #createParametersListTable} instead. + */ + @Deprecated @Nullable protected JComponent getRowPresentation(ParameterTableModelItemBase item, boolean selected, boolean focused) { return null; @@ -673,4 +685,35 @@ public abstract class ChangeSignatureDialogBase item); + + @Override + protected abstract boolean isRowEmpty(int row); + + protected ParameterTableModelItem getRowItem(int row) { + return myParametersTable.getItems().get(row); + } + } } diff --git a/platform/platform-api/src/com/intellij/ide/caches/CachesInvalidator.java b/platform/platform-api/src/com/intellij/ide/caches/CachesInvalidator.java index d5d133e33f31..4d2eddaf7f4f 100644 --- a/platform/platform-api/src/com/intellij/ide/caches/CachesInvalidator.java +++ b/platform/platform-api/src/com/intellij/ide/caches/CachesInvalidator.java @@ -23,7 +23,9 @@ public abstract class CachesInvalidator { /** - * @return description of the caches to be cleared, shown in the warning dialog to the user + * @return description of the files to be cleared, shown in the warning dialog to the user. + * When to use: when invalidation will lead to the loss of a potentially valuable to the user information, e.g. Local History. + * Do not use: when caches are easily re-buildable and doesn't contain user's data (to avoid unnecessary confusion). */ @Nullable public String getDescription() { return null; } diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/CheckboxAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/CheckboxAction.java index 3e52f26d0b87..0347ee2b5c46 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/CheckboxAction.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/CheckboxAction.java @@ -58,7 +58,7 @@ public abstract class CheckboxAction extends ToggleAction implements CustomCompo ActionManager.getInstance(), 0)); } }); - + updateCustomComponent(checkBox, presentation); return checkBox; } @@ -70,14 +70,17 @@ public abstract class CheckboxAction extends ToggleAction implements CustomCompo if (property instanceof JCheckBox) { JCheckBox checkBox = (JCheckBox)property; - checkBox.setText(presentation.getText()); - checkBox.setToolTipText(presentation.getDescription()); - checkBox.setMnemonic(presentation.getMnemonic()); - checkBox.setDisplayedMnemonicIndex(presentation.getDisplayedMnemonicIndex()); - checkBox.setSelected(Boolean.TRUE.equals(presentation.getClientProperty(SELECTED_PROPERTY))); - - checkBox.setEnabled(presentation.isEnabled()); - checkBox.setVisible(presentation.isVisible()); + updateCustomComponent(checkBox, presentation); } } + + protected void updateCustomComponent(JCheckBox checkBox, Presentation presentation) { + checkBox.setText(presentation.getText()); + checkBox.setToolTipText(presentation.getDescription()); + checkBox.setMnemonic(presentation.getMnemonic()); + checkBox.setDisplayedMnemonicIndex(presentation.getDisplayedMnemonicIndex()); + checkBox.setSelected(Boolean.TRUE.equals(presentation.getClientProperty(SELECTED_PROPERTY))); + checkBox.setEnabled(presentation.isEnabled()); + checkBox.setVisible(presentation.isVisible()); + } } diff --git a/platform/platform-api/src/com/intellij/openapi/wm/FocusCommand.java b/platform/platform-api/src/com/intellij/openapi/wm/FocusCommand.java index f948b2c54252..837dc540629d 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/FocusCommand.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/FocusCommand.java @@ -190,6 +190,7 @@ public abstract class FocusCommand extends ActiveRunnable implements Expirable { }); } + if (commandCreationTime > lastProcessedCommandTime) { if (!(myToFocus.requestFocusInWindow())) { if (shouldLogFocuses) { diff --git a/platform/platform-api/src/com/intellij/ui/GroupedElementsRenderer.java b/platform/platform-api/src/com/intellij/ui/GroupedElementsRenderer.java index 4a2abb304aa2..a7bdb9f1bb62 100644 --- a/platform/platform-api/src/com/intellij/ui/GroupedElementsRenderer.java +++ b/platform/platform-api/src/com/intellij/ui/GroupedElementsRenderer.java @@ -25,7 +25,7 @@ import javax.swing.tree.TreeCellRenderer; import java.awt.*; public abstract class GroupedElementsRenderer { - public static final Color POPUP_SEPARATOR_FOREGROUND = new JBColor(Color.gray.brighter(), Gray._43); + public static final Color POPUP_SEPARATOR_FOREGROUND = new JBColor(Color.gray.brighter(), Gray.x51); public static final Color POPUP_SEPARATOR_TEXT_FOREGROUND = Color.gray; public static final Color SELECTED_FRAME_FOREGROUND = Color.black; diff --git a/platform/platform-api/src/com/intellij/ui/TableToolbarDecorator.java b/platform/platform-api/src/com/intellij/ui/TableToolbarDecorator.java index 980d6ae50af6..af62010bc1c0 100644 --- a/platform/platform-api/src/com/intellij/ui/TableToolbarDecorator.java +++ b/platform/platform-api/src/com/intellij/ui/TableToolbarDecorator.java @@ -120,8 +120,7 @@ class TableToolbarDecorator extends ToolbarDecorator { table.setColumnSelectionInterval(0, 0); table.editCellAt(index, 0); - boolean temporaryHideVerticalScrollBar = table.getCellEditor() instanceof Animated; - TableUtil.updateScroller(table, temporaryHideVerticalScrollBar); + TableUtil.updateScroller(table); //noinspection SSBasedInspection SwingUtilities.invokeLater(new Runnable() { @Override @@ -145,7 +144,7 @@ class TableToolbarDecorator extends ToolbarDecorator { if (TableUtil.doRemoveSelectedItems(table, tableModel, null)) { updateButtons(); table.requestFocus(); - TableUtil.updateScroller(table, false); + TableUtil.updateScroller(table); } } }; diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ActivateToolWindowAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ActivateToolWindowAction.java index 9546ac55d6e7..fdfcf564bce1 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ActivateToolWindowAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ActivateToolWindowAction.java @@ -29,6 +29,7 @@ import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.impl.ToolWindowImpl; import com.intellij.ui.SizedIcon; +import com.intellij.ui.content.Content; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -102,14 +103,31 @@ public class ActivateToolWindowAction extends DumbAwareAction { presentation.setIcon(icon == null ? null : new SizedIcon(icon, icon.getIconHeight(), icon.getIconHeight())); } - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(final AnActionEvent e) { Project project = getEventProject(e); if (project == null) return; ToolWindowManager windowManager = ToolWindowManager.getInstance(project); - if (windowManager.isEditorComponentActive() || !myToolWindowId.equals(windowManager.getActiveToolWindowId())) { - windowManager.getToolWindow(myToolWindowId).activate(null); + final ToolWindow window = windowManager.getToolWindow(myToolWindowId); + InputEvent event = e.getInputEvent(); + Runnable run = null; + if (event instanceof KeyEvent && event.isShiftDown()) { + final Content[] contents = window.getContentManager().getContents(); + if (contents.length > 0 && window.getContentManager().getSelectedContent() != contents[0]) { + run = new Runnable() { + public void run() { + window.getContentManager().setSelectedContent(contents[0], true, true); + } + }; + } } - else { + + if (windowManager.isEditorComponentActive() || !myToolWindowId.equals(windowManager.getActiveToolWindowId()) || run != null) { + if (run != null && window.isActive()) { + run.run(); + } else { + window.activate(run); + } + } else { windowManager.getToolWindow(myToolWindowId).hide(null); } } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHeaderPanel.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHeaderPanel.java index bfae989b2e26..050f02c1fd8d 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHeaderPanel.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHeaderPanel.java @@ -18,7 +18,7 @@ package com.intellij.ide.plugins; import com.intellij.icons.AllIcons; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationNamesInfo; -import com.intellij.openapi.options.newEditor.IdeSettingsDialog; +import com.intellij.openapi.options.newEditor.SettingsDialog; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.GraphicsConfig; import com.intellij.openapi.wm.IdeFocusManager; @@ -281,8 +281,9 @@ public class PluginHeaderPanel { public void run() { final DialogWrapper settings = DialogWrapper.findInstance(IdeFocusManager.findInstance().getFocusOwner()); - if (settings instanceof IdeSettingsDialog) { - ((IdeSettingsDialog)settings).doOKAction(); + if (settings instanceof SettingsDialog) { + ((SettingsDialog)settings).doOKAction(); + ApplicationManager.getApplication().restart(); } else { ApplicationManager.getApplication().restart(); } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties index 5ddd24560338..aa9a302e0b1f 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties @@ -65,7 +65,7 @@ TabbedPane.contentBorderInsets=3,1,1,1 TabbedPane.darkShadow=292b2d TabbedPane.shadow=3c3f41 -Separator.foreground=2d2d2d +Separator.foreground=515151 Focus.color=ff0000 diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/CompositeDiffPanel.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/CompositeDiffPanel.java index 21c583219108..5310addbf6b8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/CompositeDiffPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/CompositeDiffPanel.java @@ -25,7 +25,9 @@ import com.intellij.openapi.diff.impl.external.DiscloseMultiRequest; import com.intellij.openapi.diff.impl.external.MultiLevelDiffTool; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Pair; import com.intellij.ui.content.Content; +import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,6 +35,7 @@ import javax.swing.*; import java.awt.*; import java.util.HashMap; import java.util.Map; +import java.util.Set; /** * Created with IntelliJ IDEA. @@ -47,7 +50,7 @@ public class CompositeDiffPanel implements DiffViewer { private final DiscloseMultiRequest myRequest; private final Window myWindow; private final Disposable myParentDisposable; - private final Map myMap; + private final Map> myMap; public CompositeDiffPanel(Project project, final DiscloseMultiRequest request, final Window window, @NotNull Disposable parentDisposable) { myRequest = request; @@ -57,7 +60,7 @@ public class CompositeDiffPanel implements DiffViewer { myUi.getComponent().setBorder(null); myUi.getOptions().setMinimizeActionEnabled(false); //myUi.getOptions().setTopToolbar() - myMap = new HashMap(); + myMap = new HashMap>(); } @Override @@ -68,59 +71,47 @@ public class CompositeDiffPanel implements DiffViewer { @Override public void setDiffRequest(DiffRequest request) { final Map requestMap = myRequest.discloseRequest(request); - final HashMap copy = new HashMap(myMap); + + HashMap> mapCopy = new HashMap>(myMap); + myMap.clear(); for (Map.Entry entry : requestMap.entrySet()) { final String key = entry.getKey(); final DiffRequest diffRequest = entry.getValue(); diffRequest.getGenericData().put(PlatformDataKeys.COMPOSITE_DIFF_VIEWER.getName(), this); - final DiffViewer viewer = copy.remove(key); + final Pair pair = mapCopy.get(key); + DiffViewer viewer = pair != null ? pair.first : null; if (viewer != null && viewer.acceptsType(diffRequest.getType()) && viewer.canShowRequest(diffRequest)) { viewer.setDiffRequest(diffRequest); + myMap.put(key, pair); + mapCopy.remove(key); } else { - if (viewer != null) { - removeTab(myUi.getContentManager().getContents(), key); - } final DiffViewer newViewer = myRequest.viewerForRequest(myWindow, myParentDisposable, key, diffRequest); if (newViewer == null) continue; - myMap.put(key, newViewer); final Content content = myUi.createContent(key, newViewer.getComponent(), key, null, newViewer.getPreferredFocusedComponent()); content.setCloseable(false); content.setPinned(true); - Disposer.register(myParentDisposable, new Disposable() { - @Override - public void dispose() { - myMap.remove(key); - myUi.removeContent(content, true); - } - }); + content.setDisposer(myParentDisposable); myUi.addContent(content); + myMap.put(key, Pair.create(newViewer, content)); + if (pair != null) myUi.removeContent(pair.second, false); } } - final Content[] contents = myUi.getContentManager().getContents(); - for (String s : copy.keySet()) { - removeTab(contents, s); - } if (myMap.isEmpty()) { - final ErrorDiffViewer errorDiffViewer = new ErrorDiffViewer(request); - myMap.put(FICTIVE_KEY, errorDiffViewer); + final ErrorDiffViewer errorDiffViewer = new ErrorDiffViewer(myWindow, request); final Content content = myUi.createContent(FICTIVE_KEY, errorDiffViewer.getComponent(), FICTIVE_KEY, null, errorDiffViewer.getPreferredFocusedComponent()); content.setCloseable(false); content.setPinned(true); content.setDisposer(myParentDisposable); myUi.addContent(content); + myMap.put(FICTIVE_KEY, Pair.create(errorDiffViewer, content)); } - } - private void removeTab(Content[] contents, String s) { - myMap.remove(s); - for (Content content : contents) { - if (s.equals(content.getDisplayName())) { - myUi.getContentManager().removeContent(content, false); - break; - } + for (Pair pair : mapCopy.values()) { + myUi.removeContent(pair.second, false); + if (pair.first instanceof Disposable) Disposer.dispose((Disposable)pair.first); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSideView.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSideView.java index 2e1758d430d1..068f52679c3d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSideView.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSideView.java @@ -255,7 +255,10 @@ public class DiffSideView { public JComponent getFocusableComponent() { Editor editor = getEditor(); - return editor != null ? editor.getContentComponent() : MOCK_COMPONENT; + if (editor != null) return editor.getContentComponent(); + FileEditor fileEditor = myEditorSource.getFileEditor(); + if (fileEditor != null) return fileEditor.getComponent(); + return MOCK_COMPONENT; } public void becomeMaster() { diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/ErrorDiffViewer.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/ErrorDiffViewer.java index f03e05d68df2..99ff6abebae5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/ErrorDiffViewer.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/ErrorDiffViewer.java @@ -36,8 +36,64 @@ import java.awt.*; public class ErrorDiffViewer implements DiffViewer { @NotNull private final DiffRequest myRequest; - protected ErrorDiffViewer(@NotNull DiffRequest request) { + @NotNull private final JPanel myPanel; + @NotNull private final DiffToolbarComponent myToolbar; + + protected ErrorDiffViewer(Window window, @NotNull DiffRequest request) { myRequest = request; + + myPanel = new AbstractDataProviderPanel(new BorderLayout(), false) { + @Override + public void calcData(DataKey key, DataSink sink) { + final Object data = myRequest.getGenericData().get(key.getName()); + if (data != null) { + sink.put(key, data); + } + } + }; + myPanel.setFocusable(true); + + final ActionManager actionManager = ActionManager.getInstance(); + myToolbar = new DiffToolbarComponent(myPanel); + final DiffRequest.ToolbarAddons addons = new DiffRequest.ToolbarAddons() { + @Override + public void customize(DiffToolbar toolbar) { + toolbar.addAction(actionManager.getAction("DiffPanel.Toolbar")); + toolbar.addAction(actionManager.getAction("ContextHelp")); + toolbar.addSeparator(); + } + }; + myToolbar.resetToolbar(addons); + final DiffToolbarImpl toolbar = myToolbar.getToolbar(); + myRequest.customizeToolbar(toolbar); + /*group.addAction(actionManager.getAction("Diff.PrevChange")); + group.addAction(actionManager.getAction("Diff.NextChange"));*/ + + myPanel.add(myToolbar, BorderLayout.NORTH); + + DiffContent content1 = myRequest.getContents()[0]; + DiffContent content2 = myRequest.getContents()[1]; + + String message; + if (DiffUtil.oneIsUnknown(content1, content2)) { + message = DiffBundle.message("diff.can.not.show.unknown"); + } + else { + message = DiffBundle.message("diff.can.not.show"); + } + + final JPanel messagePanel = createMessagePanel(message); + myPanel.add(messagePanel, BorderLayout.CENTER); + + setWindowTitle(window, request.getWindowTitle()); + } + + private static void setWindowTitle(Window window, String title) { + if (title == null || title.isEmpty()) title = "Diff"; + if (window instanceof JDialog) { + ((JDialog)window).setTitle(title); + } + else if (window instanceof JFrame) ((JFrame)window).setTitle(title); } @Override @@ -52,48 +108,7 @@ public class ErrorDiffViewer implements DiffViewer { @Override public JComponent getComponent() { - final JPanel result = new AbstractDataProviderPanel(new BorderLayout(), false) { - @Override - public void calcData(DataKey key, DataSink sink) { - final Object data = myRequest.getGenericData().get(key.getName()); - if (data != null) { - sink.put(key, data); - } - } - }; - - final ActionManager actionManager = ActionManager.getInstance(); - final DiffToolbarComponent toolbarComponent = new DiffToolbarComponent(result); - final DiffRequest.ToolbarAddons addons = new DiffRequest.ToolbarAddons() { - @Override - public void customize(DiffToolbar toolbar) { - toolbar.addAction(actionManager.getAction("DiffPanel.Toolbar")); - toolbar.addAction(actionManager.getAction("ContextHelp")); - toolbar.addSeparator(); - } - }; - toolbarComponent.resetToolbar(addons); - final DiffToolbarImpl toolbar = toolbarComponent.getToolbar(); - myRequest.customizeToolbar(toolbar); - /*group.addAction(actionManager.getAction("Diff.PrevChange")); - group.addAction(actionManager.getAction("Diff.NextChange"));*/ - - result.add(toolbarComponent, BorderLayout.NORTH); - - DiffContent content1 = myRequest.getContents()[0]; - DiffContent content2 = myRequest.getContents()[1]; - - String message; - if (DiffUtil.oneIsUnknown(content1, content2)) { - message = DiffBundle.message("diff.can.not.show.unknown"); - } - else { - message = DiffBundle.message("diff.can.not.show"); - } - - final JPanel messagePanel = createMessagePanel(message); - result.add(messagePanel, BorderLayout.CENTER); - return result; + return myPanel; } @NotNull @@ -109,7 +124,7 @@ public class ErrorDiffViewer implements DiffViewer { @Nullable @Override public JComponent getPreferredFocusedComponent() { - return null; + return myPanel; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index dde4f6cc6c75..edc4b642d25a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -432,6 +432,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } Color color = myEditor.getColorsScheme().getColor(EditorColors.LINE_NUMBERS_COLOR); + g.setColor(color != null ? color : JBColor.blue); g.setFont(myEditor.getColorsScheme().getFont(EditorFontType.PLAIN)); Graphics2D g2 = (Graphics2D)g; @@ -453,8 +454,10 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse if (logLine >= 0) { String s = String.valueOf(logLine + 1); int startY = (i + 1) * lineHeight; - Color fgColor = myTextFgColors.get(i); - g.setColor(fgColor != null ? fgColor : color != null ? color : JBColor.blue); + if (myEditor.isInDistractionFreeMode()) { + Color fgColor = myTextFgColors.get(i); + g.setColor(fgColor != null ? fgColor : color != null ? color : JBColor.blue); + } g.drawString(s, getLineNumberAreaOffset() + getLineNumberAreaWidth() - myEditor.getFontMetrics(Font.PLAIN).stringWidth(s) - diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java index c80a222ffd96..fdfeaaf29afa 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java @@ -17,10 +17,9 @@ package com.intellij.openapi.options.ex; import com.intellij.ide.ui.search.SearchUtil; -import com.intellij.openapi.ui.GraphicsConfig; import com.intellij.ui.ColorUtil; +import com.intellij.ui.JBColor; import com.intellij.ui.components.JBTabbedPane; -import com.intellij.util.ui.GraphicsUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.Nullable; @@ -30,7 +29,6 @@ import java.awt.geom.Area; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.Kernel; -import java.util.ArrayList; import java.util.HashSet; import java.util.Set; @@ -60,19 +58,15 @@ public class GlassPanel extends JComponent { public void paintSpotlight(final Graphics g, final JComponent surfaceComponent) { Dimension size = surfaceComponent.getSize(); if (myLightComponents.size() > 0) { - int width = size.width - 1; - int height = size.height - 1; + int stroke = 2; - Rectangle2D screen = new Rectangle2D.Double(0, 0, width, height); final Rectangle visibleRect = myPanel.getVisibleRect(); final Point leftPoint = SwingUtilities.convertPoint(myPanel, new Point(visibleRect.x, visibleRect.y), surfaceComponent); Area innerPanel = new Area(new Rectangle2D.Double(leftPoint.x, leftPoint.y, visibleRect.width, visibleRect.height)); - Area mask = new Area(screen); - ArrayList components = new ArrayList(); + Area mask = new Area(new Rectangle(-stroke, -stroke, 2 * stroke + size.width, 2 * stroke + size.height)); for (JComponent lightComponent : myLightComponents) { final Area area = getComponentArea(surfaceComponent, lightComponent, 1); if (area == null) continue; - components.add(lightComponent); if (lightComponent instanceof JLabel) { final JLabel label = (JLabel)lightComponent; @@ -80,7 +74,6 @@ public class GlassPanel extends JComponent { if (labelFor instanceof JComponent) { final Area labelForArea = getComponentArea(surfaceComponent, (JComponent)labelFor, 1); if (labelForArea != null) { - components.add((JComponent)labelFor); area.add(labelForArea); } } @@ -89,35 +82,28 @@ public class GlassPanel extends JComponent { area.intersect(innerPanel); mask.subtract(area); } + Graphics clip = g.create(0, 0, size.width, size.height); + try { + Graphics2D g2 = (Graphics2D)clip; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE); - Graphics2D g2 = (Graphics2D)g; + Color background = surfaceComponent.getBackground(); + g2.setColor(ColorUtil.toAlpha(background == null ? null : background.darker(), 100)); + g2.fill(mask); - Color shieldColor = new Color(0.0f, 0.0f, 0.0f, 0.20f); - Color boundsColor = Color.gray; - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.setColor(shieldColor); - g2.fill(mask); - - g2.setColor(ColorUtil.toAlpha(Color.orange, 25)); - GraphicsConfig config = GraphicsUtil.setupAAPainting(g2); - for (int i = 2; i > 0; i--) { - g2.setStroke(new BasicStroke(i)); - Area arrr = new Area(); - for (JComponent component : components) { - Area area = getComponentArea(surfaceComponent, component, i-1); - if (area != null) { - arrr.add(area); - } - } - g2.draw(arrr); + g2.setStroke(new BasicStroke(stroke)); + g2.setColor(ColorUtil.toAlpha(JBColor.ORANGE, 100)); + g2.draw(mask); + } + finally { + clip.dispose(); } - - config.restore(); } } @Nullable - private Area getComponentArea(final JComponent surfaceComponent, final JComponent lightComponent, int offset) { + private static Area getComponentArea(final JComponent surfaceComponent, final JComponent lightComponent, int offset) { if (!lightComponent.isShowing()) return null; final Point panelPoint = SwingUtilities.convertPoint(lightComponent, new Point(0, 0), surfaceComponent); @@ -173,6 +159,9 @@ public class GlassPanel extends JComponent { public void removeSpotlight(final JComponent component){ myLightComponents.remove(component); + if (myLightComponents.isEmpty()) { + setVisible(false); + } } public void clear() { diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java index c1fc29165974..743d292f89d2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java @@ -133,7 +133,7 @@ public class SettingsDialog extends DialogWrapper implements DataProvider { } @Override - protected void doOKAction() { + public void doOKAction() { if (myEditor.apply()) { ApplicationManager.getApplication().saveAll(); super.doOKAction(); diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/playback/commands/AbstractCommand.java b/platform/platform-impl/src/com/intellij/openapi/ui/playback/commands/AbstractCommand.java index fb4d031fe4f3..270374ba6c3d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/playback/commands/AbstractCommand.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/playback/commands/AbstractCommand.java @@ -64,7 +64,13 @@ public abstract class AbstractCommand implements PlaybackCommand { Runnable runnable = new Runnable() { @Override public void run() { - _execute(context).notify(result); + try { + _execute(context).notify(result); + } + catch (Throwable e) { + context.error(e.getMessage(), getLine()); + result.setRejected(); + } } }; @@ -82,7 +88,7 @@ public abstract class AbstractCommand implements PlaybackCommand { return result; } - catch (Exception e) { + catch (Throwable e) { context.error(e.getMessage(), getLine()); return new ActionCallback.Rejected(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index 598d13fcb830..0e840ee296de 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -1374,7 +1374,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements return false; } final Stripe stripe = myToolWindowsPane.getStripeFor(toolWindowId); - return stripe.getButtonFor(toolWindowId) != null; + return stripe != null && stripe.getButtonFor(toolWindowId) != null; } @Override @@ -1397,6 +1397,9 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements } final Stripe stripe = myToolWindowsPane.getStripeFor(toolWindowId); + if (stripe == null) { + return; + } final ToolWindowImpl window = getInternalDecorator(toolWindowId).getToolWindow(); if (!window.isAvailable()) { window.setPlaceholderMode(true); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java index 2df9549e8cee..89394b0d4263 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java @@ -332,6 +332,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable { return myLayeredPane; } + @Nullable private StripeButton getButtonById(final String id) { return myId2Button.get(id); } @@ -443,7 +444,13 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable { } } + @Nullable Stripe getStripeFor(String id) { + ToolWindow window = myManager.getToolWindow(id); + if (window == null) { + return null; + } + final ToolWindowAnchor anchor = myManager.getToolWindow(id).getAnchor(); if (ToolWindowAnchor.TOP == anchor) { return myTopStripe; @@ -461,6 +468,7 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable { throw new IllegalArgumentException("Anchor=" + anchor); } + @Nullable Stripe getStripeFor(final Rectangle screenRec, Stripe preferred) { if (preferred.containsScreen(screenRec)) { return myStripes.get(myStripes.indexOf(preferred)); @@ -816,32 +824,37 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable { } }); } - InternalDecorator oldComponent = (InternalDecorator)getComponentAt(anchor); - if (myInfo.isSplit()) { - splitter.setFirstComponent(oldComponent); - splitter.setSecondComponent(myNewComponent); - float proportion = getPreferredSplitProportion(oldComponent.getWindowInfo().getId(), - normalizeWeigh(oldComponent.getWindowInfo().getSideWeight() / - (oldComponent.getWindowInfo().getSideWeight() + - myInfo.getSideWeight()))); - splitter.setProportion(proportion); - if (!anchor.isHorizontal() && !anchor.isSplitVertically()) { - newWeight = normalizeWeigh(oldComponent.getWindowInfo().getWeight() + myInfo.getWeight()); + JComponent c = getComponentAt(anchor); + if (c instanceof InternalDecorator) { + InternalDecorator oldComponent = (InternalDecorator)c; + if (myInfo.isSplit()) { + splitter.setFirstComponent(oldComponent); + splitter.setSecondComponent(myNewComponent); + float proportion = getPreferredSplitProportion(oldComponent.getWindowInfo().getId(), + normalizeWeigh(oldComponent.getWindowInfo().getSideWeight() / + (oldComponent.getWindowInfo().getSideWeight() + + myInfo.getSideWeight()))); + splitter.setProportion(proportion); + if (!anchor.isHorizontal() && !anchor.isSplitVertically()) { + newWeight = normalizeWeigh(oldComponent.getWindowInfo().getWeight() + myInfo.getWeight()); + } + else { + newWeight = normalizeWeigh(oldComponent.getWindowInfo().getWeight()); + } } else { - newWeight = normalizeWeigh(oldComponent.getWindowInfo().getWeight()); - } - } - else { - splitter.setFirstComponent(myNewComponent); - splitter.setSecondComponent(oldComponent); - splitter.setProportion(normalizeWeigh(myInfo.getSideWeight())); - if (!anchor.isHorizontal() && !anchor.isSplitVertically()) { - newWeight = normalizeWeigh(oldComponent.getWindowInfo().getWeight() + myInfo.getWeight()); - } - else { - newWeight = normalizeWeigh(myInfo.getWeight()); + splitter.setFirstComponent(myNewComponent); + splitter.setSecondComponent(oldComponent); + splitter.setProportion(normalizeWeigh(myInfo.getSideWeight())); + if (!anchor.isHorizontal() && !anchor.isSplitVertically()) { + newWeight = normalizeWeigh(oldComponent.getWindowInfo().getWeight() + myInfo.getWeight()); + } + else { + newWeight = normalizeWeigh(myInfo.getWeight()); + } } + } else { + newWeight = normalizeWeigh(myInfo.getWeight()); } setComponent(splitter, anchor, newWeight); @@ -1046,16 +1059,20 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable { public void run() { try { - Splitter splitter = (Splitter)getComponentAt(myInfo.getAnchor()); - - if (myInfo.isSplit()) { - InternalDecorator component = (InternalDecorator)splitter.getFirstComponent(); - myId2SplitProportion.put(component.getWindowInfo().getId(), splitter.getProportion()); - setComponent(component, myInfo.getAnchor(), component.getWindowInfo().getWeight()); - } - else { - InternalDecorator component = (InternalDecorator)splitter.getSecondComponent(); - setComponent(component, myInfo.getAnchor(), component.getWindowInfo().getWeight()); + JComponent c = getComponentAt(myInfo.getAnchor()); + if (c instanceof Splitter) { + Splitter splitter = (Splitter)c; + if (myInfo.isSplit()) { + InternalDecorator component = (InternalDecorator)splitter.getFirstComponent(); + myId2SplitProportion.put(component.getWindowInfo().getId(), splitter.getProportion()); + setComponent(component, myInfo.getAnchor(), component.getWindowInfo().getWeight()); + } + else { + InternalDecorator component = (InternalDecorator)splitter.getSecondComponent(); + setComponent(component, myInfo.getAnchor(), component.getWindowInfo().getWeight()); + } + } else { + setComponent(null, myInfo.getAnchor(), 0); } if (!myDirtyMode) { myLayeredPane.validate(); @@ -1161,7 +1178,12 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable { public void run() { try { - WindowInfoImpl info = getButtonById(myId).getWindowInfo(); + StripeButton stripeButton = getButtonById(myId); + if (stripeButton == null) { + return; + } + + WindowInfoImpl info = stripeButton.getWindowInfo(); ToolWindowAnchor anchor = info.getAnchor(); if (ToolWindowAnchor.TOP == anchor) { diff --git a/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java b/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java index 42556dd45175..f4b719465ddc 100644 --- a/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java +++ b/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java @@ -18,9 +18,10 @@ package com.intellij.platform; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.ComponentWithBrowseButton; +import com.intellij.openapi.ui.ComponentWithBrowseButton.BrowseFolderActionListener; import com.intellij.openapi.ui.TextComponentAccessor; import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.DocumentAdapter; @@ -35,9 +36,9 @@ import javax.swing.text.PlainDocument; import java.io.File; /** - * User: catherine - *

* Logic for updating 2 fields: name for new directory and it's base location + * + * @author catherine */ public class LocationNameFieldsBinding { private boolean myModifyingLocation = false; @@ -46,60 +47,59 @@ public class LocationNameFieldsBinding { private String myBaseDir; private String mySuggestedProjectName; - public LocationNameFieldsBinding(@Nullable Project project, final TextFieldWithBrowseButton locationTextField, - final JTextField nameTextField, String baseDir, final String browseFolderTitle) { - + public LocationNameFieldsBinding(@Nullable Project project, + final TextFieldWithBrowseButton locationField, + final JTextField nameField, + String baseDir, + String title) { myBaseDir = baseDir; File suggestedProjectDirectory = FileUtil.findSequentNonexistentFile(new File(baseDir), "untitled", ""); - locationTextField.setText(suggestedProjectDirectory.toString()); - nameTextField.setDocument(new NameFieldDocument(nameTextField, locationTextField)); + locationField.setText(suggestedProjectDirectory.toString()); + nameField.setDocument(new NameFieldDocument(nameField, locationField)); mySuggestedProjectName = suggestedProjectDirectory.getName(); - nameTextField.setText(mySuggestedProjectName); - nameTextField.selectAll(); + nameField.setText(mySuggestedProjectName); + nameField.selectAll(); FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); - ComponentWithBrowseButton.BrowseFolderActionListener listener = - new ComponentWithBrowseButton.BrowseFolderActionListener(browseFolderTitle, "", locationTextField, - project, - descriptor, - TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT) { + BrowseFolderActionListener listener = + new BrowseFolderActionListener(title, "", locationField, project, descriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT) { @Override protected void onFileChosen(@NotNull VirtualFile chosenFile) { myBaseDir = chosenFile.getPath(); - if (isProjectNameChanged(nameTextField.getText()) && !nameTextField.getText().equals(chosenFile.getName())) { + if (isProjectNameChanged(nameField.getText()) && !nameField.getText().equals(chosenFile.getName())) { myExternalModify = true; - locationTextField.setText(new File(chosenFile.getPath(), nameTextField.getText()).toString()); + locationField.setText(new File(chosenFile.getPath(), nameField.getText()).toString()); myExternalModify = false; } else { myExternalModify = true; - locationTextField.setText(chosenFile.getPath()); - nameTextField.setText(chosenFile.getName()); + locationField.setText(chosenFile.getPath()); + nameField.setText(chosenFile.getName()); myExternalModify = false; } } }; - locationTextField.addActionListener(listener); - locationTextField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + locationField.addActionListener(listener); + locationField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { if (myExternalModify) { return; } myModifyingLocation = true; - String path = locationTextField.getText().trim(); + String path = locationField.getText().trim(); if (path.endsWith(File.separator)) { path = path.substring(0, path.length() - File.separator.length()); } int ind = path.lastIndexOf(File.separator); if (ind != -1) { String projectName = path.substring(ind + 1, path.length()); - if (!nameTextField.getText().trim().isEmpty()) { + if (!nameField.getText().trim().isEmpty()) { myBaseDir = path.substring(0, ind); } - if (!projectName.equals(nameTextField.getText())) { + if (!projectName.equals(nameField.getText())) { if (!myModifyingProjectName) { - nameTextField.setText(projectName); + nameField.setText(projectName); } } } @@ -112,7 +112,6 @@ public class LocationNameFieldsBinding { return !currentName.equals(mySuggestedProjectName); } - private class NameFieldDocument extends PlainDocument { public NameFieldDocument(final JTextField projectNameTextField, final TextFieldWithBrowseButton locationField) { addDocumentListener(new DocumentAdapter() { @@ -129,14 +128,25 @@ public class LocationNameFieldsBinding { @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { - boolean ok = true; - for (int idx = 0; idx < str.length() && ok; idx++) { - char ch = str.charAt(idx); - ok = ch != File.separatorChar && ch != '\\' && ch != '/' && ch != '|' && ch != ':'; + StringBuilder sb = null; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + boolean replace = c == '\\' || c == '/' || SystemInfo.isWindows && (c == '|' || c == ':'); + if (replace) { + if (sb == null) { + sb = new StringBuilder(str.length()); + sb.append(str.substring(0, i)); + } + sb.append('_'); + } + else if (sb != null) { + sb.append(c); + } } - if (ok) { - super.insertString(offs, str, a); + if (sb != null) { + str = sb.toString(); } + super.insertString(offs, str, a); } } } diff --git a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectAction.java b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectAction.java index ef4198b5deae..fc50287afd54 100644 --- a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectAction.java +++ b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectAction.java @@ -47,6 +47,7 @@ import java.io.File; public class NewDirectoryProjectAction extends AnAction implements DumbAware { private static final Logger LOG = Logger.getInstance(NewDirectoryProjectAction.class); + @Override public void actionPerformed(@NotNull AnActionEvent e) { Project project = e.getProject(); NewDirectoryProjectDialog dlg = new NewDirectoryProjectDialog(project); diff --git a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form index 4b1d4deab6d2..e38949ac3713 100644 --- a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form +++ b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form @@ -1,6 +1,6 @@

- + @@ -17,19 +17,6 @@ - - - - - - - - - - - - - @@ -38,45 +25,40 @@ + + + + + + + + - - + - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + - + - - - - + diff --git a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java index 757782851e80..9f7e6eb9ca74 100644 --- a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java +++ b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.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. @@ -15,9 +15,8 @@ */ package com.intellij.platform; -import com.intellij.facet.ui.FacetEditorValidator; -import com.intellij.facet.ui.FacetValidatorsManager; import com.intellij.facet.ui.ValidationResult; +import com.intellij.ide.IdeBundle; import com.intellij.ide.impl.ProjectUtil; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; @@ -31,7 +30,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.DocumentEvent; -import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; @@ -40,143 +38,93 @@ import java.util.List; * @author yole */ public class NewDirectoryProjectDialog extends DialogWrapper { - private JTextField myProjectNameTextField; - private TextFieldWithBrowseButton myLocationField; - protected JPanel myRootPane; - protected JComboBox myProjectTypeComboBox; - private JPanel myProjectTypePanel; - private JLabel myLocationLabel; - - protected JPanel getPlaceHolder() { - return myPlaceHolder; - } - - private JPanel myPlaceHolder; - private static final Object EMPTY_PROJECT_GENERATOR = new Object(); - private final DirectoryProjectGenerator myGeneratorBeforeSeparator; - protected NewDirectoryProjectDialog(Project project) { + private JPanel myRootPane; + private JTextField myProjectNameTextField; + private JLabel myLocationLabel; + private TextFieldWithBrowseButton myLocationField; + private JComboBox myProjectTypeComboBox; + + @SuppressWarnings("unchecked") + protected NewDirectoryProjectDialog(@Nullable Project project) { super(project, true); - setTitle("Create New Project"); + setTitle(IdeBundle.message("new.dir.project.title")); init(); myLocationLabel.setLabelFor(myLocationField.getChildComponent()); - new LocationNameFieldsBinding(project, myLocationField, myProjectNameTextField, ProjectUtil.getBaseDir(), "Select Location for Project Directory"); + String title = IdeBundle.message("new.dir.project.chooser.title"); + new LocationNameFieldsBinding(project, myLocationField, myProjectNameTextField, ProjectUtil.getBaseDir(), title); - final DirectoryProjectGenerator[] generators = getGenerators(); - if (generators.length == 0) { - myProjectTypePanel.setVisible(false); - myGeneratorBeforeSeparator = null; - } - else { - DefaultComboBoxModel model = new DefaultComboBoxModel(); - model.addElement(getEmptyProjectGenerator()); + DefaultComboBoxModel model = new DefaultComboBoxModel(); + model.addElement(EMPTY_PROJECT_GENERATOR); + + DirectoryProjectGenerator[] generators = Extensions.getExtensions(DirectoryProjectGenerator.EP_NAME); + if (generators.length > 0) { List primaryGenerators = ContainerUtil.newArrayList(); List otherGenerators = ContainerUtil.newArrayList(); for (DirectoryProjectGenerator generator : generators) { - if (generator instanceof HideableProjectGenerator) { - if (((HideableProjectGenerator)generator).isHidden()) { - continue; - } + if (generator instanceof HideableProjectGenerator && ((HideableProjectGenerator)generator).isHidden()) { + continue; } - boolean primary = true; - if (generator instanceof WebProjectGenerator) { - primary = ((WebProjectGenerator) generator).isPrimaryGenerator(); - } - if (primary) { + if (generator instanceof WebProjectGenerator && ((WebProjectGenerator)generator).isPrimaryGenerator()) { primaryGenerators.add(generator); - } else { + } + else { otherGenerators.add(generator); } } - if (!primaryGenerators.isEmpty() && !otherGenerators.isEmpty()) { - myGeneratorBeforeSeparator = primaryGenerators.get(primaryGenerators.size() - 1); - } - else { - myGeneratorBeforeSeparator = null; - } - for (DirectoryProjectGenerator generator : primaryGenerators) { - model.addElement(generator); - } - for (DirectoryProjectGenerator generator : otherGenerators) { - model.addElement(generator); - } - myProjectTypeComboBox.setModel(model); - myProjectTypeComboBox.setRenderer(createProjectTypeListCellRenderer(myProjectTypeComboBox.getRenderer())); + for (DirectoryProjectGenerator generator : primaryGenerators) model.addElement(generator); + for (DirectoryProjectGenerator generator : otherGenerators) model.addElement(generator); } + myProjectTypeComboBox.setModel(model); + myProjectTypeComboBox.setRenderer(createProjectTypeListCellRenderer()); - registerValidators(new FacetValidatorsManager() { - public void registerValidator(FacetEditorValidator validator, JComponent... componentsToWatch) { + myLocationField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + checkValid(); } - - public void validate() { + }); + myProjectTypeComboBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(@NotNull ActionEvent e) { checkValid(); } }); } @NotNull - private ListCellRenderer createProjectTypeListCellRenderer(@NotNull final ListCellRenderer originalRenderer) { - ListCellRenderer intermediate = myGeneratorBeforeSeparator == null ? originalRenderer : new ListCellRenderer() { - - private final JSeparator mySeparator = new JSeparator(SwingConstants.HORIZONTAL); - private final JPanel myComponentWithSeparator = new JPanel(new BorderLayout(0, 0)); - + private static ListCellRendererWrapper createProjectTypeListCellRenderer() { + return new ListCellRendererWrapper() { @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - Component original = originalRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - if (index != -1 && value == myGeneratorBeforeSeparator - && value instanceof DirectoryProjectGenerator && original instanceof JLabel) { - myComponentWithSeparator.removeAll(); - - JLabel label = (JLabel) original; - label.setText(((DirectoryProjectGenerator) value).getName()); - myComponentWithSeparator.add(label, BorderLayout.CENTER); - myComponentWithSeparator.add(mySeparator, BorderLayout.SOUTH); - - myComponentWithSeparator.revalidate(); - myComponentWithSeparator.repaint(); - return myComponentWithSeparator; - } - return original; - } - }; - return new ListCellRendererWrapper() { - @Override - public void customize(final JList list, final Object value, final int index, final boolean selected, final boolean cellHasFocus) { - if (value == null) return; + public void customize(JList list, Object value, int index, boolean selected, boolean cellHasFocus) { if (value == EMPTY_PROJECT_GENERATOR) { - setText("Empty project"); + setText(IdeBundle.message("new.dir.project.default.generator")); } - else { + else if (value != null) { setText(((DirectoryProjectGenerator)value).getName()); } } }; } - protected Object getEmptyProjectGenerator() { - return EMPTY_PROJECT_GENERATOR; - } - - protected DirectoryProjectGenerator[] getGenerators() { - return Extensions.getExtensions(DirectoryProjectGenerator.EP_NAME); - } - - protected void checkValid() { + private void checkValid() { String projectName = myProjectNameTextField.getText(); + if (projectName.trim().isEmpty()) { setOKActionEnabled(false); - setErrorText("Project name can't be empty"); + setErrorText(IdeBundle.message("new.dir.project.error.empty")); return; } + if (myLocationField.getText().indexOf('$') >= 0) { setOKActionEnabled(false); - setErrorText("Project directory name must not contain the $ character"); + setErrorText(IdeBundle.message("new.dir.project.error.buck")); return; } + DirectoryProjectGenerator generator = getProjectGenerator(); if (generator != null) { String baseDirPath = myLocationField.getTextField().getText(); @@ -187,58 +135,33 @@ public class NewDirectoryProjectDialog extends DialogWrapper { return; } } + setOKActionEnabled(true); setErrorText(null); } - private void registerValidators(final FacetValidatorsManager validatorsManager) { - validateOnTextChange(validatorsManager, myLocationField.getTextField()); - validateOnSelectionChange(validatorsManager, myProjectTypeComboBox); - } - - private static void validateOnSelectionChange(final FacetValidatorsManager validatorsManager, final JComboBox projectNameTextField) { - projectNameTextField.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - validatorsManager.validate(); - } - }); - } - - private static void validateOnTextChange(final FacetValidatorsManager validatorsManager, final JTextField textField) { - textField.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(DocumentEvent e) { - validatorsManager.validate(); - } - }); - } - - protected JComponent createCenterPanel() { - return myRootPane; - } - - public String getNewProjectLocation() { - return myLocationField.getText(); - } - - public String getNewProjectName() { - return myProjectNameTextField.getText(); - } - - @Nullable - public DirectoryProjectGenerator getProjectGenerator() { - final Object selItem = myProjectTypeComboBox.getSelectedItem(); - if (selItem == EMPTY_PROJECT_GENERATOR) return null; - return (DirectoryProjectGenerator)selItem; - } - + @Override public JComponent getPreferredFocusedComponent() { return myProjectNameTextField; } + @Override + protected JComponent createCenterPanel() { + return myRootPane; + } + @Override protected String getHelpId() { return "create_new_project_dialog"; } + + public String getNewProjectLocation() { + return myLocationField.getText(); + } + + @Nullable + public DirectoryProjectGenerator getProjectGenerator() { + Object item = myProjectTypeComboBox.getSelectedItem(); + return item == EMPTY_PROJECT_GENERATOR ? null : (DirectoryProjectGenerator)item; + } } diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java index e4a30d230ea9..122003fc9419 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java @@ -20,6 +20,7 @@ import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.impl.DelegateColorScheme; import com.intellij.openapi.editor.event.DocumentListener; @@ -30,7 +31,9 @@ import com.intellij.openapi.editor.impl.RangeMarkerTree; import com.intellij.openapi.editor.markup.HighlighterLayer; import com.intellij.openapi.editor.markup.HighlighterTargetArea; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.openapi.util.text.StringUtil; @@ -56,31 +59,54 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, private static final Key MY_PANEL_PROPERTY = Key.create("EditorTextFieldCellRenderer.MyEditorPanel"); - public EditorTextFieldCellRenderer(Disposable parent) { + private final Project myProject; + private final boolean myInheritFontFromLaF; + + protected EditorTextFieldCellRenderer(@Nullable Project project, @NotNull Disposable parent) { + this(project, true, parent); + } + + protected EditorTextFieldCellRenderer(@Nullable Project project, boolean inheritFontFromLaF, @NotNull Disposable parent) { + myProject = project; + myInheritFontFromLaF = inheritFontFromLaF; Disposer.register(parent, this); } - protected abstract EditorColorsScheme getColorScheme(); - - protected abstract String getText(FontMetrics fontMetrics, JTable table, Object value, int row, int column); + protected abstract String getText(JTable table, Object value, int row, int column); @Nullable - protected abstract TextAttributes getTextAttributes(Object value, boolean selected, int row, int col); + protected TextAttributes getTextAttributes(JTable table, Object value, boolean selected, boolean focused, int row, int col) { + return null; + } + + protected Color getCellBackground(JTable table, Object value, boolean selected, boolean focused, int row, int column) { + return UIUtil.getTableBackground(selected); + } + + @Nullable + protected FileType getFileType() { + return null; + } + + @NotNull + protected EditorColorsScheme getColorScheme() { + return EditorColorsManager.getInstance().getGlobalScheme(); + } @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int column) { MyPanel panel = getEditorPanel(table); EditorEx editor = panel.myEditor; editor.getColorsScheme().setEditorFontSize(table.getFont().getSize()); - String text = getText(((EditorImpl)editor).getFontMetrics(Font.PLAIN), table, value, row, column); - TextAttributes textAttributes = getTextAttributes(value, isSelected, row, column); + String text = getText(table, value, row, column); + TextAttributes textAttributes = getTextAttributes(table, value, selected, focused, row, column); panel.setText(text, textAttributes); - ((EditorImpl)editor).setPaintSelection(isSelected); - editor.getSelectionModel().setSelection(0, isSelected ? editor.getDocument().getTextLength() : 0); + ((EditorImpl)editor).setPaintSelection(selected); + editor.getSelectionModel().setSelection(0, selected ? editor.getDocument().getTextLength() : 0); editor.getColorsScheme().setColor(EditorColors.SELECTION_BACKGROUND_COLOR, table.getSelectionBackground()); editor.getColorsScheme().setColor(EditorColors.SELECTION_FOREGROUND_COLOR, table.getSelectionForeground()); - editor.setBackgroundColor(getCellBackgroundColor(getColorScheme(), table, isSelected, row)); + editor.setBackgroundColor(getCellBackground(table, value, selected, focused, row, column)); panel.setOpaque(!Comparing.equal(editor.getBackgroundColor(), table.getBackground())); panel.setBorder(null); // prevents double border painting when ExtendedItemRendererComponentWrapper is used @@ -88,14 +114,8 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, return panel; } - public static Color getCellBackgroundColor(EditorColorsScheme colorsScheme, JTable table, boolean isSelected, int row) { - return isSelected ? table.getSelectionBackground() : - table.getSelectionModel().getLeadSelectionIndex() == row ? colorsScheme.getColor(EditorColors.CARET_ROW_COLOR) : - table.getBackground(); - } - @NotNull - private MyPanel getEditorPanel(JTable table) { + private MyPanel getEditorPanel(final JTable table) { MyPanel panel = UIUtil.getClientProperty(table, MY_PANEL_PROPERTY); if (panel != null) { DelegateColorScheme scheme = (DelegateColorScheme)panel.myEditor.getColorsScheme(); @@ -103,10 +123,10 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, return panel; } - // reuse EditorTextField initialization logic - EditorTextField field = new EditorTextField(new MyDocument(), null, FileTypes.PLAIN_TEXT, false, false); + FileType fileType = ObjectUtils.notNull(getFileType(), FileTypes.PLAIN_TEXT); + EditorTextField field = new EditorTextField(new MyDocument(), myProject, fileType, false, false); field.setSupplementary(true); - field.setFontInheritedFromLAF(false); + field.setFontInheritedFromLAF(myInheritFontFromLaF); field.addNotify(); // creates editor EditorEx editor = (EditorEx)ObjectUtils.assertNotNull(field.getEditor()); @@ -119,6 +139,12 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, panel = new MyPanel(editor); Disposer.register(this, panel); + Disposer.register(this, new Disposable() { + @Override + public void dispose() { + UIUtil.putClientProperty(table, MY_PANEL_PROPERTY, null); + } + }); table.putClientProperty(MY_PANEL_PROPERTY, panel); return panel; @@ -157,6 +183,15 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, recalculatePreferredSize(); } + @Override + public void setBackground(Color bg) { + // allows for striped tables + if (myEditor != null) { + myEditor.setBackgroundColor(bg); + } + super.setBackground(bg); + } + @Override public Dimension getPreferredSize() { return myPreferredSize; diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 6f20a456c4c7..6ee1ded56642 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -525,8 +525,10 @@ public abstract class SpeedSearchBase extends SpeedSear myPopupLayeredPane.validate(); myPopupLayeredPane.repaint(); myPopupLayeredPane = null; - - Disposer.dispose(myListenerDisposable); + + if (myListenerDisposable != null) { + Disposer.dispose(myListenerDisposable); + } myListenerDisposable = null; } else if (searchPopup != null) { diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java b/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java new file mode 100644 index 000000000000..5c64391669ec --- /dev/null +++ b/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java @@ -0,0 +1,64 @@ +/* + * 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.util.ui.table; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.project.Project; +import com.intellij.ui.EditorTextFieldCellRenderer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; + +public abstract class EditorTextFieldJBTableRowRenderer extends EditorTextFieldCellRenderer implements JBTableRowRenderer { + protected EditorTextFieldJBTableRowRenderer(@Nullable Project project, @NotNull Disposable parent) { + super(project, parent); + } + + @Override + public final JComponent getRowRendererComponent(JTable table, int row, boolean selected, boolean focused) { + return (JComponent)getTableCellRendererComponent(table, null, selected, focused, row, 0); + } + + @Override + protected final String getText(JTable table, Object value, int row, int column) { + return getText(table, row); + } + + @Override + protected final Color getCellBackground(JTable table, Object value, boolean selected, boolean focused, int row, int column) { + return getRowBackground(table, selected, focused, row); + } + + @Nullable + @Override + protected final TextAttributes getTextAttributes(JTable table, Object value, boolean selected, boolean focused, int row, int col) { + return getTextAttributes(table, row); + } + + protected abstract String getText(JTable table, int row); + + @Nullable + protected TextAttributes getTextAttributes(JTable table, int row) { + return null; + } + + protected Color getRowBackground(JTable table, boolean selected, boolean focused, int row) { + return super.getCellBackground(table, null, selected, focused, row, 0); + } +} diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java index 4ab92f15293b..89cd47453b92 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java @@ -15,25 +15,33 @@ */ package com.intellij.util.ui.table; +import com.intellij.openapi.Disposable; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Ref; -import com.intellij.ui.*; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.ui.DottedBorder; +import com.intellij.ui.EditorSettingsProvider; +import com.intellij.ui.EditorTextField; +import com.intellij.ui.TableUtil; import com.intellij.ui.table.JBTable; import com.intellij.util.ui.AbstractTableCellEditor; import com.intellij.util.ui.UIUtil; +import gnu.trove.TIntArrayList; +import gnu.trove.TIntObjectHashMap; +import gnu.trove.TIntObjectProcedure; +import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.ChangeEvent; -import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; import java.awt.*; -import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; +import java.awt.event.*; import java.util.List; import static java.awt.event.KeyEvent.*; @@ -41,16 +49,18 @@ import static java.awt.event.KeyEvent.*; /** * @author Konstantin Bulenkov */ -public abstract class JBListTable extends JPanel { +public abstract class JBListTable { protected final JTable myInternalTable; private final JBTable mainTable; - private final Ref myLastEditorIndex = Ref.create(null); + private final RowResizeAnimator myRowResizeAnimator; + private final Disposable myOnRemoveDisposable; private MouseEvent myMouseEvent; private MyCellEditor myCellEditor; + private int myLastFocusedEditorComponentIdx = -1; public JBListTable(@NotNull final JTable t) { - super(new BorderLayout()); myInternalTable = t; + myOnRemoveDisposable = Disposer.newDisposable(); final JBListTableModel model = new JBListTableModel(t.getModel()) { @Override public JBTableRow getRow(int index) { @@ -64,7 +74,7 @@ public abstract class JBListTable extends JPanel { @Override public void addRow() { - myLastEditorIndex.set(null); + myLastFocusedEditorComponentIdx = -1; super.addRow(); } }; @@ -114,10 +124,11 @@ public abstract class JBListTable extends JPanel { @Override public TableCellRenderer getCellRenderer(int row, int column) { - return new DefaultTableCellRenderer() { + final JBTableRowRenderer rowRenderer = getRowRenderer(row); + return new TableCellRenderer() { @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean hasFocus, int row, int col) { - return getRowRenderer(t, row, selected, hasFocus); + public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int col) { + return rowRenderer.getRowRendererComponent(t, row, selected, focused); } }; } @@ -199,6 +210,16 @@ public abstract class JBListTable extends JPanel { return super.processKeyBinding(ks, e, condition, pressed); } + @Override + public void columnMarginChanged(ChangeEvent e) { + // we don't stop editing (it prevents editor removal when scrollbar is added) + TableColumn resizingColumn = tableHeader != null ? tableHeader.getResizingColumn() : null; + if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF) { + resizingColumn.setPreferredWidth(resizingColumn.getWidth()); + } + resizeAndRepaint(); + } + @Override public TableCellEditor getCellEditor(final int row, int column) { final JBTableRowEditor editor = getRowEditor(row); @@ -224,14 +245,31 @@ public abstract class JBListTable extends JPanel { boolean isSelected = isCellSelected(row, column); return editor.getTableCellEditorComponent(this, value, isSelected, row, column); } + + @Override + public void addNotify() { + super.addNotify(); + Disposer.register(myOnRemoveDisposable, myRowResizeAnimator); + } + + @Override + public void removeNotify() { + super.removeNotify(); + Disposer.dispose(myOnRemoveDisposable); + } }; mainTable.setStriped(true); + myRowResizeAnimator = new RowResizeAnimator(mainTable); } public void stopEditing() { TableUtil.stopEditing(mainTable); } + public Disposable getOnRemoveDisposable() { + return myOnRemoveDisposable; + } + private static void installPaddingAndBordersForEditors(JBTableRowEditor editor) { final List editors = UIUtil.findComponentsOfType(editor, EditorTextField.class); for (EditorTextField textField : editors) { @@ -244,7 +282,7 @@ public abstract class JBListTable extends JPanel { return mainTable; } - protected abstract JComponent getRowRenderer(JTable table, int row, boolean selected, boolean focused); + protected abstract JBTableRowRenderer getRowRenderer(int row); protected abstract JBTableRowEditor getRowEditor(int row); @@ -296,118 +334,49 @@ public abstract class JBListTable extends JPanel { return panel; } - private static class RowResizeAnimator extends Thread { - private final JTable myTable; - private final int myRow; - private final JScrollPane myScrollPane; - private int neededHeight; - private final JBTableRowEditor myEditor; - private final Ref myIndex; - private int step = 5; - private int currentHeight; - - private RowResizeAnimator(JTable table, int row, int height, JBTableRowEditor editor, @NotNull Ref index) { - super("Row Animator"); - myTable = table; - myRow = row; - neededHeight = height; - myEditor = editor; - myIndex = index; - currentHeight = myTable.getRowHeight(myRow); - myScrollPane = UIUtil.getParentOfType(JScrollPane.class, myTable); - } - - @Override - public void run() { - final boolean exitEditing = currentHeight > neededHeight; - try { - sleep(50); - final JScrollBar bar = myScrollPane.getVerticalScrollBar(); - if (bar == null || !bar.isVisible()) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - myScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); - } - }); - sleep(15); - } - while (currentHeight != neededHeight) { - if (Math.abs(currentHeight - neededHeight) < step) { - currentHeight = neededHeight; - } - else { - currentHeight += currentHeight < neededHeight ? step : -step; - } - SwingUtilities.invokeLater(new Runnable() { - public void run() { - myTable.setRowHeight(myRow, currentHeight); - } - }); - sleep(15); - } - if (myEditor != null) { - JComponent[] components = myEditor.getFocusableComponents(); - JComponent focus = null; - if (myIndex.get() != null) { - int index = myIndex.get().intValue(); - if (0 <= index && index < components.length) { - focus = components[index]; - } - } - if (focus == null) { - focus = myEditor.getPreferredFocusedComponent(); - } - if (focus != null) { - focus.requestFocus(); - } - } - } - catch (InterruptedException ignore) { - } finally { - //noinspection SSBasedInspection - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - TableUtil.scrollSelectionToVisible(myTable); - if (exitEditing && !myTable.isEditing()) { - myScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); - } - } - }); - } - } - } - - private class MyCellEditor extends AbstractTableCellEditor implements Animated { - JTable curTable; + private class MyCellEditor extends AbstractTableCellEditor { private final JBTableRowEditor myEditor; public MyCellEditor(JBTableRowEditor editor) { myEditor = editor; - curTable = null; } @Override public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, final int row, int column) { - curTable = table; final JPanel p = new JPanel(new BorderLayout()) { @Override public void addNotify() { super.addNotify(); - final int height = (int)getPreferredSize().getHeight(); + int height = getPreferredSize().height; if (height > table.getRowHeight(row)) { - new RowResizeAnimator(table, row, height, myEditor, myMouseEvent == null ? myLastEditorIndex : Ref.create(null)).start(); + myRowResizeAnimator.resize(row, height); } } public void removeNotify() { if (myCellEditor != null) myCellEditor.saveFocusIndex(); super.removeNotify(); - new RowResizeAnimator(table, row, table.getRowHeight(), null, myMouseEvent == null ? myLastEditorIndex : Ref.create(null)).start(); + myRowResizeAnimator.resize(row, table.getRowHeight()); } }; + p.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + IdeFocusManager focusManager = IdeFocusManager.findInstanceByComponent(p); + focusManager.requestFocus(getComponentToFocus(), true); + } + + private Component getComponentToFocus() { + if (myLastFocusedEditorComponentIdx >= 0) { + JComponent[] focusableComponents = myEditor.getFocusableComponents(); + if (myLastFocusedEditorComponentIdx < focusableComponents.length) { + return focusableComponents[myLastFocusedEditorComponentIdx]; + } + } + return myEditor.getPreferredFocusedComponent(); + } + }); p.add(myEditor, BorderLayout.CENTER); - p.setFocusable(false); return p; } @@ -422,31 +391,107 @@ public abstract class JBListTable extends JPanel { return super.stopCellEditing(); } - private void removeEmptyRow() { - final int row = curTable.getSelectedRow(); - if (row != -1 && isRowEmpty(row)) { - final JBListTableModel model = (JBListTableModel)curTable.getModel(); - final int count = model.getRowCount(); - model.removeRow(row); - int newRow = count == row + 1 ? row - 1 : row; - curTable.setRowSelectionInterval(newRow, newRow); - } - } - - public void saveFocusIndex() { - JComponent[] components = myEditor.getFocusableComponents(); - for (int i = 0; i < components.length; i++) { - if (components[i].hasFocus()) { - JBListTable.this.myLastEditorIndex.set(i); - break; - } - } - } - @Override public void cancelCellEditing() { saveFocusIndex(); super.cancelCellEditing(); } + + private void saveFocusIndex() { + JComponent[] components = myEditor.getFocusableComponents(); + for (int i = 0; i < components.length; i++) { + if (components[i].hasFocus()) { + myLastFocusedEditorComponentIdx = i; + break; + } + } + } + } + + private static class RowResizeAnimator implements ActionListener, Disposable { + private static final int ANIMATION_STEP_MILLIS = 15; + private static final int RESIZE_AMOUNT_PER_STEP = 5; + + private final TIntObjectHashMap myRowAnimationStates = new TIntObjectHashMap(); + private final Timer myAnimationTimer = new Timer(ANIMATION_STEP_MILLIS, this); + private final JTable myTable; + + public RowResizeAnimator(JTable table) { + myTable = table; + } + + public void resize(int row, int targetHeight) { + myRowAnimationStates.put(row, new RowAnimationState(row, targetHeight)); + startAnimation(); + } + + @Override + public void actionPerformed(final ActionEvent e) { + doAnimationStep(e.getWhen()); + } + + @Override + public void dispose() { + stopAnimation(); + } + + private void startAnimation() { + if (!myAnimationTimer.isRunning()) { + myAnimationTimer.start(); + } + } + + private void stopAnimation() { + myAnimationTimer.stop(); + } + + private void doAnimationStep(final long updateTime) { + final TIntArrayList completeRows = new TIntArrayList(myRowAnimationStates.size()); + myRowAnimationStates.forEachEntry(new TIntObjectProcedure() { + @Override + public boolean execute(int row, RowAnimationState animationState) { + if (animationState.doAnimationStep(updateTime)) { + completeRows.add(row); + } + return true; + } + }); + completeRows.forEach(new TIntProcedure() { + @Override + public boolean execute(int row) { + myRowAnimationStates.remove(row); + return true; + } + }); + if (myRowAnimationStates.isEmpty()) { + stopAnimation(); + } + } + + private class RowAnimationState { + private final int myRow; + private final int myTargetHeight; + private long myLastUpdateTime; + + public RowAnimationState(int row, int targetHeight) { + myRow = row; + myTargetHeight = targetHeight; + myLastUpdateTime = System.currentTimeMillis(); + } + + /** + * @return whether this row animation is complete + */ + public boolean doAnimationStep(long currentTime) { + int currentRowHeight = myTable.getRowHeight(myRow); + int resizeAbs = (int) (RESIZE_AMOUNT_PER_STEP * ((currentTime - myLastUpdateTime) / (double)ANIMATION_STEP_MILLIS)); + int leftToAnimate = myTargetHeight - currentRowHeight; + int newHeight = Math.abs(leftToAnimate) <= Math.abs(resizeAbs) ? myTargetHeight : + currentRowHeight + (leftToAnimate < 0 ? -resizeAbs : resizeAbs); + myTable.setRowHeight(myRow, newHeight); + myLastUpdateTime = currentTime; + return myTargetHeight == newHeight; + } + } } } diff --git a/platform/platform-api/src/com/intellij/ui/Animated.java b/platform/platform-impl/src/com/intellij/util/ui/table/JBTableRowRenderer.java similarity index 66% rename from platform/platform-api/src/com/intellij/ui/Animated.java rename to platform/platform-impl/src/com/intellij/util/ui/table/JBTableRowRenderer.java index 26c6b0bc3a40..25630353c298 100644 --- a/platform/platform-api/src/com/intellij/ui/Animated.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/JBTableRowRenderer.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. @@ -13,13 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.ui; +package com.intellij.util.ui.table; -/** - * Indicates that component, or cell editor, or cell renderer performs - * some animations and side effects may occur because of changes of the bounds - * - * @author Konstantin Bulenkov - */ -public interface Animated { +import javax.swing.*; + +public interface JBTableRowRenderer { + JComponent getRowRendererComponent(JTable table, int row, boolean selected, boolean focused); } diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java b/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java index 63d38ed57fcb..48c07843ab99 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java @@ -371,7 +371,7 @@ public class TableModelEditor implements ElementProducer { } table.requestFocus(); - TableUtil.updateScroller(table, false); + TableUtil.updateScroller(table); } } ).createPanel(); @@ -440,7 +440,7 @@ public class TableModelEditor implements ElementProducer { public void run(AnActionButton button) { if (TableUtil.doRemoveSelectedItems(table, model, this)) { table.requestFocus(); - TableUtil.updateScroller(table, false); + TableUtil.updateScroller(table); } } diff --git a/platform/platform-resources-en/src/messages/ExecutionBundle.properties b/platform/platform-resources-en/src/messages/ExecutionBundle.properties index b2f05abc66bd..a2177d38107c 100644 --- a/platform/platform-resources-en/src/messages/ExecutionBundle.properties +++ b/platform/platform-resources-en/src/messages/ExecutionBundle.properties @@ -207,7 +207,7 @@ failed.to.generate.wrapper.error.message=Failed to generate temporary html wrapp application.configuration.use.classpath.and.jdk.of.module.label=Use classpath of m&odule: application.configuration.main.class.label=Main &class: -jre.path.is.not.valid.jre.home.error.mesage=''{0}'' is not valid JRE home +jre.path.is.not.valid.jre.home.error.mesage=''{0}'' is not a valid JRE home main.method.not.found.in.class.error.message=Main method not found in class {0} no.user.process.input.error.message=No process input fix.run.configuration.problem.button=Fix diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 1e25c84ddf16..53aa439998a3 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -1155,3 +1155,9 @@ presentation.mode.fon.size=Font size\: update.available.group=Update Checker loading.editors=Loading files... + +new.dir.project.title=Create New Project +new.dir.project.chooser.title=Select Location for Project Directory +new.dir.project.default.generator=Empty project +new.dir.project.error.empty=Project name can't be empty +new.dir.project.error.buck=Project directory name must not contain the ''$'' character diff --git a/platform/platform-resources-en/src/messages/RefactoringBundle.properties b/platform/platform-resources-en/src/messages/RefactoringBundle.properties index 72b1cd7ad131..6dac3b8e726c 100644 --- a/platform/platform-resources-en/src/messages/RefactoringBundle.properties +++ b/platform/platform-resources-en/src/messages/RefactoringBundle.properties @@ -397,6 +397,7 @@ introduce.constant.field.of.type=Constant (static final field) of &type: extract.subclass.command=Extract Subclass extract.superclass.elements.header=Extract superclass with members to directory declare.static.checkbox=Declare &static +declare.static.pass.fields.checkbox=Declare &static (pass fields as params) declare.varargs.checkbox=Declare v&arargs declare.folded.parameters=&Fold parameters extract.method.method.panel.border=Method diff --git a/platform/platform-resources/src/idea/Keymap_Default.xml b/platform/platform-resources/src/idea/Keymap_Default.xml index 8907cc61f633..248fc702bbb4 100644 --- a/platform/platform-resources/src/idea/Keymap_Default.xml +++ b/platform/platform-resources/src/idea/Keymap_Default.xml @@ -836,6 +836,7 @@ + diff --git a/platform/platform-resources/src/idea/Keymap_Mac.xml b/platform/platform-resources/src/idea/Keymap_Mac.xml index 0cbcef8c36e0..d72aeb713e14 100644 --- a/platform/platform-resources/src/idea/Keymap_Mac.xml +++ b/platform/platform-resources/src/idea/Keymap_Mac.xml @@ -214,6 +214,7 @@ + diff --git a/platform/platform-resources/src/idea/Keymap_MacClassic.xml b/platform/platform-resources/src/idea/Keymap_MacClassic.xml index bd4e97e6d743..80eb6a4610a4 100644 --- a/platform/platform-resources/src/idea/Keymap_MacClassic.xml +++ b/platform/platform-resources/src/idea/Keymap_MacClassic.xml @@ -217,6 +217,7 @@ + diff --git a/platform/platform-resources/src/idea/Keymap_Xcode.xml b/platform/platform-resources/src/idea/Keymap_Xcode.xml index 049ee8d62025..68d6177376f4 100644 --- a/platform/platform-resources/src/idea/Keymap_Xcode.xml +++ b/platform/platform-resources/src/idea/Keymap_Xcode.xml @@ -26,6 +26,7 @@ + diff --git a/platform/util/testSrc/com/intellij/openapi/ui/SplitterTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/ui/SplitterTest.java similarity index 92% rename from platform/util/testSrc/com/intellij/openapi/ui/SplitterTest.java rename to platform/platform-tests/testSrc/com/intellij/openapi/ui/SplitterTest.java index a2819d61e804..85c3253279ad 100644 --- a/platform/util/testSrc/com/intellij/openapi/ui/SplitterTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/ui/SplitterTest.java @@ -30,7 +30,7 @@ public class SplitterTest extends TestCase{ resizeTest(new Splitter(false)); } - private void resizeTest(Splitter splitter) { + private static void resizeTest(Splitter splitter) { JPanel jPanel1 = new JPanel(); jPanel1.setMinimumSize(new Dimension(100, 100)); JPanel jPanel2 = new JPanel(); @@ -48,9 +48,11 @@ public class SplitterTest extends TestCase{ splitter.doLayout(); checkBounds(splitter); - splitter.setProportion(.1f); - splitter.doLayout(); - checkBounds(splitter); + for (float proportion = 0; proportion <= 1; proportion+=0.01) { + splitter.setProportion(proportion); + splitter.doLayout(); + checkBounds(splitter); + } splitter.setProportion(.9f); splitter.doLayout(); @@ -86,7 +88,7 @@ public class SplitterTest extends TestCase{ } - private void checkBounds(Splitter splitter) { + private static void checkBounds(Splitter splitter) { Dimension firstSize = splitter.getFirstComponent().getSize(); Dimension secondSize = splitter.getSecondComponent().getSize(); diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java index c9963a4f8f40..6c667cbafb0e 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java @@ -555,9 +555,11 @@ public class SMTestProxy extends AbstractTestProxy { return (AssertEqualsDiffViewerProvider)myState; } - for (SMTestProxy child : myChildren) { - if (child.myState instanceof AssertEqualsDiffViewerProvider) { - return (AssertEqualsDiffViewerProvider)child.myState; + if (myChildren != null) { + for (SMTestProxy child : myChildren) { + if (child.myState instanceof AssertEqualsDiffViewerProvider) { + return (AssertEqualsDiffViewerProvider)child.myState; + } } } return null; diff --git a/platform/testFramework/src/_FirstInSuiteTest.java b/platform/testFramework/src/_FirstInSuiteTest.java index 3d4a5576e8d0..b66fc2af5d82 100644 --- a/platform/testFramework/src/_FirstInSuiteTest.java +++ b/platform/testFramework/src/_FirstInSuiteTest.java @@ -25,7 +25,10 @@ import javax.swing.*; */ @SuppressWarnings("JUnitTestClassNamingConvention") public class _FirstInSuiteTest extends TestCase { + public static long suiteStarted = 0L; + public void testNothing() throws Exception { + suiteStarted = System.nanoTime(); SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { diff --git a/platform/testFramework/src/_LastInSuiteTest.java b/platform/testFramework/src/_LastInSuiteTest.java index 3c953560e86b..f5a4e063b10e 100644 --- a/platform/testFramework/src/_LastInSuiteTest.java +++ b/platform/testFramework/src/_LastInSuiteTest.java @@ -63,6 +63,11 @@ public class _LastInSuiteTest extends TestCase { @SuppressWarnings("UseOfSystemOutOrSystemErr") public void testStatistics() throws Exception { + if (_FirstInSuiteTest.suiteStarted != 0) { + long testSuiteDuration = System.nanoTime() - _FirstInSuiteTest.suiteStarted; + System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.totalTimeMs' value='%d']", + testSuiteDuration / 1000000)); + } LightPlatformTestCase.reportTestExecutionStatistics(); } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java index 6be1c2ae4a9d..2cd323c0fa8f 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java @@ -281,7 +281,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { /** * Runs highlighting test for the given files. - * The same as {@link #testHighlighting(boolean, boolean, boolean, String...)} with all options set. + * The same as {@link #testHighlighting(boolean, boolean, boolean, String...)} with {@code checkInfos=false}. * * @param filePaths the first file is tested only; the others are just copied along with the first. * @return highlighting duration in milliseconds diff --git a/platform/util/src/com/intellij/openapi/ui/Splitter.java b/platform/util/src/com/intellij/openapi/ui/Splitter.java index 71a026702563..ca0ea83c7fe1 100644 --- a/platform/util/src/com/intellij/openapi/ui/Splitter.java +++ b/platform/util/src/com/intellij/openapi/ui/Splitter.java @@ -286,7 +286,7 @@ public class Splitter extends JPanel { } int iSize1 = (int)Math.round(Math.floor(size1)); - int iSize2 = (int)Math.round(total - size1 - d); + int iSize2 = total - iSize1 - d; if (isVertical()) { firstRect.setBounds(0, 0, width, iSize1); diff --git a/platform/util/src/com/intellij/ui/TableUtil.java b/platform/util/src/com/intellij/ui/TableUtil.java index 53d55d3b78b9..070acf4cec19 100644 --- a/platform/util/src/com/intellij/ui/TableUtil.java +++ b/platform/util/src/com/intellij/ui/TableUtil.java @@ -244,15 +244,9 @@ public class TableUtil { column.setMinWidth(checkboxWidth); } - public static void updateScroller(@NotNull JTable table, boolean temporaryHideVerticalScrollBar) { + public static void updateScroller(@NotNull JTable table) { JScrollPane scrollPane = UIUtil.getParentOfType(JScrollPane.class, table); if (scrollPane != null) { - if (temporaryHideVerticalScrollBar) { - final JScrollBar bar = scrollPane.getVerticalScrollBar(); - if (bar == null || !bar.isVisible()) { - scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); - } - } scrollPane.revalidate(); scrollPane.repaint(); } diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java index 26c681d738f3..e511d3f4c2d6 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java @@ -805,7 +805,7 @@ public final class ConcurrentHashMap extends AbstractMap /** * Creates a new, empty map with the default initial table size (16). */ - ConcurrentHashMap() { + public ConcurrentHashMap() { this(DEFAULT_CAPACITY); } @@ -819,7 +819,7 @@ public final class ConcurrentHashMap extends AbstractMap * @throws IllegalArgumentException if the initial capacity of * elements is negative */ - ConcurrentHashMap(int initialCapacity) { + public ConcurrentHashMap(int initialCapacity) { this(initialCapacity, LOAD_FACTOR); } @@ -828,7 +828,7 @@ public final class ConcurrentHashMap extends AbstractMap * * @param m the map */ - ConcurrentHashMap(Map m) { + public ConcurrentHashMap(Map m) { this(DEFAULT_CAPACITY); putAll(m); } @@ -847,7 +847,7 @@ public final class ConcurrentHashMap extends AbstractMap * elements is negative or the load factor is nonpositive * @since 1.6 */ - ConcurrentHashMap(int initialCapacity, float loadFactor) { + public ConcurrentHashMap(int initialCapacity, float loadFactor) { this(initialCapacity, loadFactor, 1); } @@ -869,7 +869,7 @@ public final class ConcurrentHashMap extends AbstractMap * negative or the load factor or concurrencyLevel are * nonpositive */ - ConcurrentHashMap(int initialCapacity, + public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { this(initialCapacity, loadFactor, concurrencyLevel, THIS); } @@ -886,7 +886,7 @@ public final class ConcurrentHashMap extends AbstractMap } }; - ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy hashingStrategy) { + public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy hashingStrategy) { if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) { throw new IllegalArgumentException(); } @@ -901,7 +901,7 @@ public final class ConcurrentHashMap extends AbstractMap myHashingStrategy = hashingStrategy == THIS ? this : hashingStrategy; } - ConcurrentHashMap(@NotNull TObjectHashingStrategy hashingStrategy) { + public ConcurrentHashMap(@NotNull TObjectHashingStrategy hashingStrategy) { this(DEFAULT_CAPACITY, LOAD_FACTOR, NCPU, hashingStrategy); } diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentHashSet.java b/platform/util/src/com/intellij/util/containers/ConcurrentHashSet.java index 2b4331a50706..aa8844c239fb 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentHashSet.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentHashSet.java @@ -24,16 +24,19 @@ import java.util.Iterator; import java.util.Set; import java.util.concurrent.ConcurrentMap; -class ConcurrentHashSet implements Set { +/** + * @deprecated use {@link ContainerUtil#newConcurrentSet()} instead + */ +public class ConcurrentHashSet implements Set { private final ConcurrentMap map; - ConcurrentHashSet(int initialCapacity) { + public ConcurrentHashSet(int initialCapacity) { map = ContainerUtil.newConcurrentMap(initialCapacity); } - ConcurrentHashSet() { + public ConcurrentHashSet() { map = ContainerUtil.newConcurrentMap(); } - ConcurrentHashSet(@NotNull TObjectHashingStrategy hashingStrategy) { + public ConcurrentHashSet(@NotNull TObjectHashingStrategy hashingStrategy) { map = ContainerUtil.newConcurrentMap(hashingStrategy); } diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentWeakKeySoftValueHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentWeakKeySoftValueHashMap.java index 332b5333572b..0746909e8f76 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentWeakKeySoftValueHashMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentWeakKeySoftValueHashMap.java @@ -49,7 +49,7 @@ public class ConcurrentWeakKeySoftValueHashMap implements ConcurrentMap myValueQueue = new ReferenceQueue(); @NotNull private final TObjectHashingStrategy myHashingStrategy; - protected ConcurrentWeakKeySoftValueHashMap(int initialCapacity, + public ConcurrentWeakKeySoftValueHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull final TObjectHashingStrategy hashingStrategy) { diff --git a/platform/util/src/com/intellij/util/ui/ColumnInfo.java b/platform/util/src/com/intellij/util/ui/ColumnInfo.java index 2ad54e6f81b9..1be6e451deea 100644 --- a/platform/util/src/com/intellij/util/ui/ColumnInfo.java +++ b/platform/util/src/com/intellij/util/ui/ColumnInfo.java @@ -55,7 +55,7 @@ public abstract class ColumnInfo { return myName; } - public Class getColumnClass() { + public Class getColumnClass() { return String.class; } diff --git a/platform/util/src/com/intellij/util/ui/ListTableModel.java b/platform/util/src/com/intellij/util/ui/ListTableModel.java index 9577ab235735..8e01d89374cc 100644 --- a/platform/util/src/com/intellij/util/ui/ListTableModel.java +++ b/platform/util/src/com/intellij/util/ui/ListTableModel.java @@ -62,7 +62,7 @@ public class ListTableModel extends TableViewModel implements Editab } @Override - public Class getColumnClass(int columnIndex) { + public Class getColumnClass(int columnIndex) { return myColumnInfos[columnIndex].getColumnClass(); } diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 25d5a66974ca..b971116fa1bf 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -39,7 +39,6 @@ import javax.sound.sampled.Clip; import javax.swing.*; import javax.swing.Timer; import javax.swing.border.Border; -import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import javax.swing.plaf.ButtonUI; @@ -227,8 +226,8 @@ public class UIUtil { private static final Color INACTIVE_HEADER_COLOR = Gray._128; private static final Color BORDER_COLOR = Color.LIGHT_GRAY; - public static final Color AQUA_SEPARATOR_FOREGROUND_COLOR = Gray._190; - public static final Color AQUA_SEPARATOR_BACKGROUND_COLOR = Gray._240; + public static final Color AQUA_SEPARATOR_FOREGROUND_COLOR = new JBColor(Gray._190, Gray.x51); + public static final Color AQUA_SEPARATOR_BACKGROUND_COLOR = new JBColor(Gray._240, Gray.x51); public static final Color TRANSPARENT_COLOR = new Color(0, 0, 0, 0); public static final int DEFAULT_HGAP = 10; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/BaseDiffFromHistoryHandler.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/BaseDiffFromHistoryHandler.java index 1417d014569e..89a44f1f165f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/BaseDiffFromHistoryHandler.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/BaseDiffFromHistoryHandler.java @@ -146,6 +146,7 @@ public abstract class BaseDiffFromHistoryHandler impl new ChangesBrowser(myProject, null, changes, null, false, true, null, ChangesBrowser.MyUseCase.COMMITTED_CHANGES, null); changesBrowser.setChangesToDisplay(changes); dialogBuilder.setCenterPanel(changesBrowser); + dialogBuilder.setPreferredFocusComponent(changesBrowser.getPreferredFocusedComponent()); dialogBuilder.showNotModal(); } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java index 9fadbda240a4..df340db6e5da 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2012 Bas Leijdekkers + * Copyright 2007-2014 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.siyeh.ipp.exceptions; +import com.intellij.codeInsight.FileModificationService; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; @@ -36,8 +37,18 @@ public class ConvertCatchToThrowsIntention extends Intention { @Override protected void processIntention(@NotNull PsiElement element) throws IncorrectOperationException { final PsiCatchSection catchSection = (PsiCatchSection)element.getParent(); - final PsiMethod method = PsiTreeUtil.getParentOfType(catchSection, PsiMethod.class); - if (method == null) { + final NavigatablePsiElement owner = PsiTreeUtil.getParentOfType(catchSection, PsiMethod.class, PsiLambdaExpression.class); + final PsiMethod method; + if (owner instanceof PsiMethod) { + method = (PsiMethod)owner; + } + else if (owner instanceof PsiLambdaExpression) { + method = LambdaUtil.getFunctionalInterfaceMethod(owner); + if (method == null || !FileModificationService.getInstance().preparePsiElementsForWrite(method)) { + return; + } + } + else { return; } // todo warn if method implements or overrides some base method diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsPredicate.java index dd7e88a49121..7e15549e10a1 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsPredicate.java @@ -1,5 +1,5 @@ /* - * Copyright 2007-2013 Bas Leijdekkers + * Copyright 2007-2014 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ class ConvertCatchToThrowsPredicate implements PsiElementPredicate { if (element instanceof PsiCodeBlock) { return false; } - final PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, true, PsiClass.class); - return method != null; + final PsiElement owner = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, PsiClass.class, PsiLambdaExpression.class); + return owner instanceof PsiMethod || owner instanceof PsiLambdaExpression; } } diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/catchToThrows/Lambda.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/catchToThrows/Lambda.java new file mode 100644 index 000000000000..da64d3ef583f --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/catchToThrows/Lambda.java @@ -0,0 +1,19 @@ +class Lambda { + + void bar() throws E {} + + void foo() { + U u = () -> { + try { + + } catch (E e) { + e.printStackTrace(); + } + }; + } + + interface U { + void f(); + } + class E extends Exception {} +} diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/catchToThrows/Lambda_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/catchToThrows/Lambda_after.java new file mode 100644 index 000000000000..c82292f3f141 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/catchToThrows/Lambda_after.java @@ -0,0 +1,16 @@ +class Lambda { + + void bar() throws E {} + + void foo() { + U u = () -> { + + + }; + } + + interface U { + void f() throws E; + } + class E extends Exception {} +} diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/exceptions/ConvertCatchToThrowsTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/exceptions/ConvertCatchToThrowsTest.java index 195a8bfb533c..4d4814fca6bd 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/exceptions/ConvertCatchToThrowsTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/exceptions/ConvertCatchToThrowsTest.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. @@ -25,6 +25,7 @@ public class ConvertCatchToThrowsTest extends IPPTestCase { public void testArmWithPluralCatches() { doTest(); } public void testArmWithSingleCatch() { doTest(); } public void testExistingThrows() { doTest(); } + public void testLambda() { doTest(); } @Override protected String getIntentionName() { diff --git a/plugins/ant/src/com/intellij/lang/ant/config/actions/AddAntBuildFile.java b/plugins/ant/src/com/intellij/lang/ant/config/actions/AddAntBuildFile.java index 5248251c66ef..1e81f9b5c746 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/actions/AddAntBuildFile.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/actions/AddAntBuildFile.java @@ -16,6 +16,7 @@ package com.intellij.lang.ant.config.actions; import com.intellij.lang.ant.AntBundle; +import com.intellij.lang.ant.config.AntBuildFile; import com.intellij.lang.ant.config.AntConfiguration; import com.intellij.lang.ant.config.AntConfigurationBase; import com.intellij.lang.ant.config.AntNoFileException; @@ -30,72 +31,94 @@ import com.intellij.psi.PsiManager; import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; public class AddAntBuildFile extends AnAction { - public void actionPerformed(AnActionEvent event) { - DataContext dataContext = event.getDataContext(); - Project project = CommonDataKeys.PROJECT.getData(dataContext); - VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); - AntConfiguration antConfiguration = AntConfiguration.getInstance(project); - try { - antConfiguration.addBuildFile(file); - ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.ANT_BUILD).activate(null); + public void actionPerformed(@NotNull AnActionEvent event) { + final DataContext dataContext = event.getDataContext(); + final Project project = CommonDataKeys.PROJECT.getData(dataContext); + if (project == null) { + return; } - catch (AntNoFileException e) { - String message = e.getMessage(); - if (message == null || message.length() == 0) { - message = AntBundle.message("cannot.add.build.files.from.excluded.directories.error.message", e.getFile().getPresentableUrl()); - } + final VirtualFile[] contextFiles = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext); + if (contextFiles == null || contextFiles.length == 0) { + return; + } + final AntConfiguration antConfiguration = AntConfiguration.getInstance(project); - Messages.showWarningDialog(project, message, AntBundle.message("cannot.add.build.file.dialog.title")); + final Set files = new HashSet(); + files.addAll(Arrays.asList(contextFiles)); + for (AntBuildFile buildFile : antConfiguration.getBuildFiles()) { + files.remove(buildFile.getVirtualFile()); + } + + int filesAdded = 0; + final StringBuilder errors = new StringBuilder(); + + for (VirtualFile file : files) { + try { + antConfiguration.addBuildFile(file); + filesAdded++; + } + catch (AntNoFileException e) { + String message = e.getMessage(); + if (message == null || message.length() == 0) { + message = AntBundle.message("cannot.add.build.files.from.excluded.directories.error.message", e.getFile().getPresentableUrl()); + } + if (errors.length() > 0) { + errors.append("\n"); + } + errors.append(message); + } + } + + if (errors.length() > 0) { + Messages.showWarningDialog(project, errors.toString(), AntBundle.message("cannot.add.build.file.dialog.title")); + } + if (filesAdded > 0) { + ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.ANT_BUILD).activate(null); } } - public void update(AnActionEvent e) { + public void update(@NotNull AnActionEvent e) { final DataContext dataContext = e.getDataContext(); final Presentation presentation = e.getPresentation(); final Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) { - disable(presentation); - return; + if (project != null) { + final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext); + if (files != null && files.length > 0) { + for (VirtualFile file : files) { + final PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + if (!(psiFile instanceof XmlFile)) { + continue; + } + final XmlFile xmlFile = (XmlFile)psiFile; + final XmlDocument document = xmlFile.getDocument(); + if (document == null) { + continue; + } + final XmlTag rootTag = document.getRootTag(); + if (rootTag == null) { + continue; + } + if (!"project".equals(rootTag.getName())) { + continue; + } + if (AntConfigurationBase.getInstance(project).getAntBuildFile(psiFile) != null) { + continue; + } + // found at least one candidate file + enable(presentation); + return; + } + } } - final VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); - if (file == null) { - disable(presentation); - return; - } - - final PsiFile psiFile = PsiManager.getInstance(project).findFile(file); - if (!(psiFile instanceof XmlFile)) { - disable(presentation); - return; - } - - final XmlFile xmlFile = (XmlFile)psiFile; - final XmlDocument document = xmlFile.getDocument(); - if (document == null) { - disable(presentation); - return; - } - - final XmlTag rootTag = document.getRootTag(); - if (rootTag == null) { - disable(presentation); - return; - } - - if (!"project".equals(rootTag.getName())) { - disable(presentation); - return; - } - - if (AntConfigurationBase.getInstance(project).getAntBuildFile(psiFile) != null) { - disable(presentation); - return; - } - - enable(presentation); + disable(presentation); } private static void enable(Presentation presentation) { diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBuildModelImpl.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBuildModelImpl.java index 673985667e3f..13ad8455ebd0 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBuildModelImpl.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBuildModelImpl.java @@ -208,6 +208,9 @@ public class AntBuildModelImpl implements AntBuildModelBase { } }.fillTargets(list, model, project, sourceFile); } + if (dependencies.isEmpty()) { + dependencies.add(PsiModificationTracker.MODIFICATION_COUNT); + } return new Pair, Collection>(list, dependencies); } diff --git a/plugins/ant/tests/data/psi/resolve/PropValueInAttributeB.ant b/plugins/ant/tests/data/psi/resolve/PropValueInAttributeB.ant index 52de75ace212..170c92ef0faf 100644 --- a/plugins/ant/tests/data/psi/resolve/PropValueInAttributeB.ant +++ b/plugins/ant/tests/data/psi/resolve/PropValueInAttributeB.ant @@ -1,5 +1,5 @@ - + diff --git a/plugins/properties/src/com/intellij/lang/properties/references/PropertiesCompletionContributor.java b/plugins/properties/src/com/intellij/lang/properties/references/PropertiesCompletionContributor.java index 686cbe65b5b7..6c4e3615ed72 100644 --- a/plugins/properties/src/com/intellij/lang/properties/references/PropertiesCompletionContributor.java +++ b/plugins/properties/src/com/intellij/lang/properties/references/PropertiesCompletionContributor.java @@ -77,7 +77,7 @@ public class PropertiesCompletionContributor extends CompletionContributor { } } - private static boolean hasMoreImportantReference(PsiReference[] references, PropertyReference propertyReference) { + public static boolean hasMoreImportantReference(@NotNull PsiReference[] references, @NotNull PropertyReference propertyReference) { return propertyReference.isSoft() && ContainerUtil.or(references, new Condition() { @Override public boolean value(PsiReference reference) { diff --git a/python/helpers/pydev/pydev_monkey_qt.py b/python/helpers/pydev/pydev_monkey_qt.py index c50213fdd7fb..06a3f47b65ad 100644 --- a/python/helpers/pydev/pydev_monkey_qt.py +++ b/python/helpers/pydev/pydev_monkey_qt.py @@ -85,6 +85,7 @@ def _internal_patch_qt(): _original_thread_init = QtCore.QThread.__init__ _original_runnable_init = QtCore.QRunnable.__init__ + _original_QThread = QtCore.QThread class FuncWrapper: @@ -113,15 +114,24 @@ def _internal_patch_qt(): class ThreadWrapper(QtCore.QThread): # Wrapper for QThread - + def __init__(self, *args, **kwargs): _original_thread_init(self) - - self._original_run = self.run - self.run = self._new_run + + # In PyQt5 the program hangs when we try to call original run method of QThread class. + # So we need to distinguish instances of QThread class and instances of QThread inheritors. + if self.__class__.run == _original_QThread.run: + self.run = self._exec_run + else: + self._original_run = self.run + self.run = self._new_run self._original_started = self.started self.started = StartedSignalWrapper(self, self.started) - + + def _exec_run(self): + set_trace_in_qt() + return self.exec_() + def _new_run(self): set_trace_in_qt() return self._original_run() diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index a967467ed3af..df5dfba3937d 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -50,10 +50,7 @@ import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; import com.intellij.ui.awt.RelativePoint; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.PlatformIcons; -import com.intellij.util.SmartList; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.NotNullPredicate; import com.jetbrains.python.PyBundle; @@ -847,13 +844,7 @@ public class PyUtil { @Nullable @SuppressWarnings("unchecked") public static T as(@Nullable final Object expression, @NotNull final Class clazz) { - if (expression == null) { - return null; - } - if (clazz.isAssignableFrom(expression.getClass())) { - return (T)expression; - } - return null; + return ObjectUtils.tryCast(expression, clazz); } // TODO: Move to PsiElement? @@ -968,24 +959,25 @@ public class PyUtil { } /** - * If target is a PsiDirectory, that is also a valid Python package, return PsiFile that points to __init__.py, + * If directory is a PsiDirectory, that is also a valid Python package, return PsiFile that points to __init__.py, * if such file exists, or directory itself (i.e. namespace package). Otherwise, return {@code null}. * Unlike {@link #turnDirIntoInit(com.intellij.psi.PsiElement)} this function handles namespace packages and * accepts only PsiDirectories as target. * - * @param target directory to check + * @param directory directory to check * @param anchor optional PSI element to determine language level as for {@link #isPackage(com.intellij.psi.PsiDirectory, com.intellij.psi.PsiElement)} * @return PsiFile or PsiDirectory, if target is a Python package and {@code null} null otherwise */ @Nullable - public static PsiElement turnDirIntoPackageElement(@NotNull PsiDirectory target, @Nullable PsiElement anchor) { - if (isPackage(target, anchor)) { - final PsiFile file = target.findFile(PyNames.INIT_DOT_PY); - return file != null ? file : target; - } - else { - return null; + public static PsiElement getPackageElement(@NotNull PsiDirectory directory, @Nullable PsiElement anchor) { + if (isPackage(directory, anchor)) { + final PsiElement init = turnDirIntoInit(directory); + if (init != null) { + return init; + } + return directory; } + return null; } /** @@ -1019,18 +1011,6 @@ public class PyUtil { return PyNames.INIT_DOT_PY.equals(file.getName()); } - @Nullable - public static PsiElement getPackageElement(@NotNull PsiDirectory directory, @Nullable PsiElement anchor) { - if (isPackage(directory, anchor)) { - final PsiElement init = turnDirIntoInit(directory); - if (init != null) { - return init; - } - return directory; - } - return null; - } - private static boolean isSetuptoolsNamespacePackage(@NotNull PsiDirectory directory) { final String packagePath = getPackagePath(directory); return packagePath != null && !PySetuptoolsNamespaceIndex.find(packagePath, directory.getProject()).isEmpty(); @@ -1165,8 +1145,8 @@ public class PyUtil { public static Collection getSourceRoots(@NotNull Module module) { final Set result = new LinkedHashSet(); final ModuleRootManager manager = ModuleRootManager.getInstance(module); - result.addAll(Arrays.asList(manager.getSourceRoots())); - result.addAll(Arrays.asList(manager.getContentRoots())); + Collections.addAll(result, manager.getSourceRoots()); + Collections.addAll(result, manager.getContentRoots()); return result; } @@ -1708,10 +1688,7 @@ public class PyUtil { private static boolean isObject(@NotNull final PyMemberInfo classMemberInfo) { final PyElement element = classMemberInfo.getMember(); - if ((element instanceof PyClass) && PyNames.OBJECT.equals(element.getName())) { - return true; - } - return false; + return (element instanceof PyClass) && PyNames.OBJECT.equals(element.getName()); } } @@ -1751,10 +1728,7 @@ public class PyUtil { */ public static boolean isObjectClass(@NotNull PyClass cls) { final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(cls); - if (cls == builtinCache.getClass(PyNames.OBJECT) || cls == builtinCache.getClass(PyNames.FAKE_OLD_BASE)) { - return true; - } - return false; + return cls == builtinCache.getClass(PyNames.OBJECT) || cls == builtinCache.getClass(PyNames.FAKE_OLD_BASE); } /** @@ -1768,9 +1742,6 @@ public class PyUtil { */ public static boolean isObjectType(@NotNull PyType type, @NotNull PsiElement anchor) { final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(anchor); - if (type == builtinCache.getObjectType() || type == builtinCache.getOldstyleClassobjType()) { - return true; - } - return false; + return type == builtinCache.getObjectType() || type == builtinCache.getOldstyleClassobjType(); } } diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 4c6535cacd5a..1a75492f2985 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -23,7 +23,6 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; @@ -175,7 +174,7 @@ public class ResolveImportUtil { if (qualifiedName == null || sourceFile == null) { return Collections.emptyList(); } - final String marker = StringUtil.join(qualifiedName.getComponents(), ".") + "#" + Integer.toString(relativeLevel); + final String marker = qualifiedName + "#" + Integer.toString(relativeLevel); final Set beingImported = ourBeingImported.get(); if (beingImported.contains(marker)) { return Collections.emptyList(); // break endless loop in import diff --git a/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java b/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java index 53f2894684e5..03711d3d22ec 100644 --- a/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java +++ b/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java @@ -297,8 +297,8 @@ public class PyRefactoringUtil { final FindUsagesHandler handler = new PyFindUsagesHandlerFactory().createFindUsagesHandler(element, forHighlightUsages); assert handler != null; final List elementsToProcess = new ArrayList(); - elementsToProcess.addAll(Arrays.asList(handler.getPrimaryElements())); - elementsToProcess.addAll(Arrays.asList(handler.getSecondaryElements())); + Collections.addAll(elementsToProcess, handler.getPrimaryElements()); + Collections.addAll(elementsToProcess, handler.getSecondaryElements()); for (PsiElement e : elementsToProcess) { handler.processElementUsages(e, new Processor() { @Override diff --git a/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java b/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java index c748731559b0..78a368005423 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java +++ b/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java @@ -245,7 +245,7 @@ public final class PyClassRefactoringUtil { final String asName = node.getCopyableUserData(ENCODED_IMPORT_AS); final Boolean useFromImport = node.getCopyableUserData(ENCODED_USE_FROM_IMPORT); if (target instanceof PsiDirectory) { - target = (PsiNamedElement)PyUtil.turnDirIntoPackageElement((PsiDirectory)target, node); + target = (PsiNamedElement)PyUtil.getPackageElement((PsiDirectory)target, node); } if (target instanceof PyFunction) { final PyFunction f = (PyFunction)target; diff --git a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java index dd233ff563d0..c08c9941c383 100644 --- a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java +++ b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java @@ -16,8 +16,10 @@ package com.jetbrains.python.refactoring.move; import com.intellij.lang.injection.InjectedLanguageManager; +import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; @@ -40,8 +42,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; -import static com.intellij.openapi.vfs.VirtualFileManager.*; - /** * @author vlan */ @@ -91,32 +91,29 @@ public class PyMoveFileHandler extends MoveFileHandler { continue; } final QualifiedName newName = QualifiedNameFinder.findShortestImportableQName(sourceElement); - final PsiElement fromKeyword = statement.getFirstChild(); - final PsiElement firstDot = fromKeyword.getNextSibling().getNextSibling(); - assert firstDot.getNode().getElementType() == PyTokenTypes.DOT; - final PsiWhiteSpace nextWhitespace = PsiTreeUtil.getNextSiblingOfType(firstDot, PsiWhiteSpace.class); - final PsiElement replacementEnd = nextWhitespace == null ? statement.getLastChild() : nextWhitespace.getPrevSibling(); - if (replacementEnd != firstDot) { - statement.deleteChildRange(firstDot.getNextSibling(), replacementEnd); - } - replaceWithQualifiedExpression(firstDot, newName); + replaceRelativeImportSourceWithQualifiedExpression(statement, newName); } } @Nullable private static PsiFileSystemItem resolveRelativeImportSourceFromModuleLocation(@NotNull String moduleLocation, @NotNull PyFromImportStatement statement) { - String relativeImportBasePath = extractPath(moduleLocation); + String relativeImportBasePath = VirtualFileManager.extractPath(moduleLocation); for (int level = 0; level < statement.getRelativeLevel(); level++) { relativeImportBasePath = PathUtil.getParentPath(relativeImportBasePath); } if (!relativeImportBasePath.isEmpty()) { - //noinspection ConstantConditions - final String relativeImportBaseUrl = constructUrl(extractProtocol(moduleLocation), relativeImportBasePath); - final VirtualFile relativeImportBaseDir = getInstance().findFileByUrl(relativeImportBaseUrl); + final String protocol = VirtualFileManager.extractProtocol(moduleLocation); + assert protocol != null : "Original location: " + moduleLocation; + final String relativeImportBaseUrl = VirtualFileManager.constructUrl(protocol, relativeImportBasePath); + final VirtualFile relativeImportBaseDir = VirtualFileManager.getInstance().findFileByUrl(relativeImportBaseUrl); VirtualFile sourceFile = relativeImportBaseDir; if (relativeImportBaseDir != null && relativeImportBaseDir.exists() && statement.getImportSource() != null) { - final String relativePath = statement.getImportSource().getText().replace('.', '/'); + final QualifiedName qualifiedName = statement.getImportSource().asQualifiedName(); + if (qualifiedName == null) { + return null; + } + final String relativePath = qualifiedName.join("/"); sourceFile = relativeImportBaseDir.findFileByRelativePath(relativePath); if (sourceFile == null) { sourceFile = relativeImportBaseDir.findFileByRelativePath(relativePath + PyNames.DOT_PY); @@ -186,8 +183,12 @@ public class PyMoveFileHandler extends MoveFileHandler { continue; } final QualifiedName newElementName = QualifiedNameFinder.findCanonicalImportPath(newElement, element); - removeLeadingDots(element); - replaceWithQualifiedExpression(element, newElementName); + if (importStmt instanceof PyFromImportStatement) { + replaceRelativeImportSourceWithQualifiedExpression((PyFromImportStatement)importStmt, newElementName); + } + else { + replaceWithQualifiedExpression(element, newElementName); + } } else if (element instanceof PyReferenceExpression) { updatedFiles.add(file); @@ -227,21 +228,58 @@ public class PyMoveFileHandler extends MoveFileHandler { return oldElement; } - private static void removeLeadingDots(@NotNull PsiElement element) { - PsiElement lastDot = null; - PsiElement firstDot = null; - for (PsiElement prev = element.getPrevSibling(); prev != null; prev = prev.getPrevSibling()) { - if (prev.getNode().getElementType() != PyTokenTypes.DOT) { - break; + /** + * Replace import source with leading dots (if any) with reference expression created from given qualified name. + * Basically it does the same thing as {@link #replaceWithQualifiedExpression}, but also removes leading dots. + * + * @param importStatement import statement to update + * @param qualifiedName qualified name of new import source + * @return updated import statement + * @see #replaceWithQualifiedExpression(com.intellij.psi.PsiElement, com.intellij.psi.util.QualifiedName) + */ + @NotNull + private static PsiElement replaceRelativeImportSourceWithQualifiedExpression(@NotNull PyFromImportStatement importStatement, + @Nullable QualifiedName qualifiedName) { + final Couple range = getRelativeImportSourceRange(importStatement); + if (range != null && qualifiedName != null) { + if (range.getFirst() == range.getSecond()) { + replaceWithQualifiedExpression(range.getFirst(), qualifiedName); } - if (lastDot == null) { - lastDot = prev; + else { + importStatement.deleteChildRange(range.getFirst().getNextSibling(), range.getSecond()); + replaceWithQualifiedExpression(range.getFirst(), qualifiedName); } - firstDot = prev; } - if (lastDot != null && firstDot != null) { - element.getParent().deleteChildRange(firstDot, lastDot); + return importStatement; + } + + @Nullable + private static Couple getRelativeImportSourceRange(@NotNull PyFromImportStatement statement) { + final PsiElement fromKeyword = statement.getFirstChild(); + assert fromKeyword.getNode().getElementType() == PyTokenTypes.FROM_KEYWORD; + final PsiElement elementAfterFrom = PsiTreeUtil.skipSiblingsForward(fromKeyword, PsiWhiteSpace.class); + if (elementAfterFrom == null) { + return null; } + else if (elementAfterFrom instanceof PyReferenceExpression) { + return Couple.of(elementAfterFrom, elementAfterFrom); + } + else if (elementAfterFrom.getNode().getElementType() == PyTokenTypes.DOT) { + PsiElement lastDot; + PsiElement next = elementAfterFrom; + do { + lastDot = next; + next = PsiTreeUtil.skipSiblingsForward(next, PsiWhiteSpace.class); + } + while (next != null && next.getNode().getElementType() == PyTokenTypes.DOT); + if (next instanceof PyReferenceExpression) { + return Couple.of(elementAfterFrom, next); + } + else { + return Couple.of(elementAfterFrom, lastDot); + } + } + return null; } @Override diff --git a/python/testData/MockSdk3.2/Lib/unittest/__init__.py b/python/testData/MockSdk3.2/Lib/unittest/__init__.py deleted file mode 100644 index 2b93ab7cc67c..000000000000 --- a/python/testData/MockSdk3.2/Lib/unittest/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .case import TestCase diff --git a/python/testData/MockSdk3.2/Lib/unittest/case.py b/python/testData/MockSdk3.2/Lib/unittest/case.py deleted file mode 100644 index fad1d5da6d97..000000000000 --- a/python/testData/MockSdk3.2/Lib/unittest/case.py +++ /dev/null @@ -1,2 +0,0 @@ -class TestCase(object): - pass \ No newline at end of file diff --git a/python/testData/MockSdk3.4/Lib/unittest/__init__.py b/python/testData/MockSdk3.4/Lib/unittest/__init__.py deleted file mode 100644 index 2b93ab7cc67c..000000000000 --- a/python/testData/MockSdk3.4/Lib/unittest/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .case import TestCase diff --git a/python/testData/MockSdk3.4/Lib/unittest/case.py b/python/testData/MockSdk3.4/Lib/unittest/case.py deleted file mode 100644 index fad1d5da6d97..000000000000 --- a/python/testData/MockSdk3.4/Lib/unittest/case.py +++ /dev/null @@ -1,2 +0,0 @@ -class TestCase(object): - pass \ No newline at end of file diff --git a/python/testData/debug/test_pyqt1.py b/python/testData/debug/test_pyqt1.py new file mode 100644 index 000000000000..5a11f2fa66f5 --- /dev/null +++ b/python/testData/debug/test_pyqt1.py @@ -0,0 +1,15 @@ +from PyQt5 import QtCore +import sys + + +class AThread(QtCore.QThread): + + def run(self): + for i in range(3): + print("ping %d" % i) + +app = QtCore.QCoreApplication([]) +thread = AThread() +thread.finished.connect(app.exit) +thread.start() +sys.exit(app.exec_()) diff --git a/python/testData/debug/test_pyqt2.py b/python/testData/debug/test_pyqt2.py new file mode 100644 index 000000000000..e8785fcf280a --- /dev/null +++ b/python/testData/debug/test_pyqt2.py @@ -0,0 +1,23 @@ +from PyQt5 import QtCore +import sys + + +class SomeObject(QtCore.QObject): + + finished = QtCore.pyqtSignal() + + def longRunning(self): + for i in range(3): + print("ping %d" % i) + self.finished.emit() + + +app = QtCore.QCoreApplication([]) +objThread = QtCore.QThread() +obj = SomeObject() +obj.moveToThread(objThread) +obj.finished.connect(objThread.quit) +objThread.started.connect(obj.longRunning) +objThread.finished.connect(app.exit) +objThread.start() +sys.exit(app.exec_()) \ No newline at end of file diff --git a/python/testData/debug/test_pyqt3.py b/python/testData/debug/test_pyqt3.py new file mode 100644 index 000000000000..a505b0070e21 --- /dev/null +++ b/python/testData/debug/test_pyqt3.py @@ -0,0 +1,19 @@ +from PyQt5 import QtCore +import sys + + +class Runnable(QtCore.QRunnable): + + def run(self): + app = QtCore.QCoreApplication.instance() + for i in range(3): + print("ping %d" % i) + app.quit() + + +app = QtCore.QCoreApplication([]) +runnable = Runnable() +QtCore.QThreadPool.globalInstance().start(runnable) +sys.exit(app.exec_()) + + diff --git a/python/testData/inspections/PyPep8NamingInspection/test.py b/python/testData/inspections/PyPep8NamingInspection/test/a.py similarity index 100% rename from python/testData/inspections/PyPep8NamingInspection/test.py rename to python/testData/inspections/PyPep8NamingInspection/test/a.py diff --git a/python/testData/MockSdk2.7/Lib/unittest/__init__.py b/python/testData/inspections/PyPep8NamingInspection/test/unittest/__init__.py similarity index 100% rename from python/testData/MockSdk2.7/Lib/unittest/__init__.py rename to python/testData/inspections/PyPep8NamingInspection/test/unittest/__init__.py diff --git a/python/testData/MockSdk2.7/Lib/unittest/case.py b/python/testData/inspections/PyPep8NamingInspection/test/unittest/case.py similarity index 100% rename from python/testData/MockSdk2.7/Lib/unittest/case.py rename to python/testData/inspections/PyPep8NamingInspection/test/unittest/case.py diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/a.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/a.py new file mode 100644 index 000000000000..6fdb98275f1e --- /dev/null +++ b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/a.py @@ -0,0 +1,3 @@ +from pkg.subpkg2.subsubpkg import b + +print(b) \ No newline at end of file diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/pkg/__init__.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/pkg/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/pkg/subpkg1/__init__.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/pkg/subpkg1/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/pkg/subpkg2/__init__.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/pkg/subpkg2/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/pkg/subpkg2/subsubpkg/__init__.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/pkg/subpkg2/subsubpkg/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/pkg/subpkg2/subsubpkg/b.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/after/src/pkg/subpkg2/subsubpkg/b.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/__init__.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/subpkg1/__init__.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/subpkg1/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/subpkg1/a.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/subpkg1/a.py new file mode 100644 index 000000000000..bfe757b9faeb --- /dev/null +++ b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/subpkg1/a.py @@ -0,0 +1,3 @@ +from .. subpkg2 . subsubpkg import b + +print(b) \ No newline at end of file diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/subpkg2/__init__.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/subpkg2/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/subpkg2/subsubpkg/__init__.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/subpkg2/subsubpkg/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/subpkg2/subsubpkg/b.py b/python/testData/refactoring/move/relativeImportSourceWithSpacesInsideMovedModule/before/src/pkg/subpkg2/subsubpkg/b.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java index 628c3826c807..4e0c3177a5e5 100644 --- a/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java +++ b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java @@ -510,6 +510,112 @@ public class PythonDebuggerTest extends PyEnvTestCase { }); } + public void testPyQtQThreadInheritor() throws Exception { + runPythonTest(new PyDebuggerTask("/debug", "test_pyqt1.py") { + @Override + protected void init() { + setMultiprocessDebug(true); + } + + @Override + public void before() throws Exception { + toggleBreakpoint(getScriptPath(), 8); + } + + @Override + public void testing() throws Exception { + + waitForPause(); + + eval("i").hasValue("0"); + + resume(); + + waitForPause(); + + eval("i").hasValue("1"); + + resume(); + } + + @Override + public Set getTags() { + return Sets.newHashSet("pyqt5"); + } + }); + } + + public void testPyQtMoveToThread() throws Exception { + runPythonTest(new PyDebuggerTask("/debug", "test_pyqt2.py") { + @Override + protected void init() { + setMultiprocessDebug(true); + } + + @Override + public void before() throws Exception { + toggleBreakpoint(getScriptPath(), 10); + } + + @Override + public void testing() throws Exception { + + waitForPause(); + + eval("i").hasValue("0"); + + resume(); + + waitForPause(); + + eval("i").hasValue("1"); + + resume(); + } + + @Override + public Set getTags() { + return Sets.newHashSet("pyqt5"); + } + }); + } + + + public void testPyQtQRunnableInheritor() throws Exception { + runPythonTest(new PyDebuggerTask("/debug", "test_pyqt3.py") { + @Override + protected void init() { + setMultiprocessDebug(true); + } + + @Override + public void before() throws Exception { + toggleBreakpoint(getScriptPath(), 9); + } + + @Override + public void testing() throws Exception { + + waitForPause(); + + eval("i").hasValue("0"); + + resume(); + + waitForPause(); + + eval("i").hasValue("1"); + + resume(); + } + + @Override + public Set getTags() { + return Sets.newHashSet("pyqt5"); + } + }); + } + //TODO: fix me as I don't work properly sometimes (something connected with process termination on agent) //public void testResume() throws Exception { diff --git a/python/testSrc/com/jetbrains/python/inspections/PyPep8NamingInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyPep8NamingInspectionTest.java index 89b8b7a877fa..63d063172435 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyPep8NamingInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyPep8NamingInspectionTest.java @@ -75,7 +75,7 @@ public class PyPep8NamingInspectionTest extends PyTestCase { } public void testTest() { - doTest(); + doMultiFileTest(); } public void testOverrideFromModule() { @@ -90,4 +90,12 @@ public class PyPep8NamingInspectionTest extends PyTestCase { myFixture.enableInspections(PyPep8NamingInspection.class); myFixture.checkHighlighting(false, false, true); } + + private void doMultiFileTest() { + myFixture.copyDirectoryToProject("inspections/PyPep8NamingInspection/" + getTestName(true), ""); + myFixture.configureByFile("a.py"); + myFixture.enableInspections(PyPep8NamingInspection.class); + myFixture.checkHighlighting(false, false, true); + } + } diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java index 7fc6872b7f4b..6ebfd283ce46 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java @@ -200,6 +200,12 @@ public class PyMoveTest extends PyTestCase { doMoveFileTest("pkg1/subpkg1", ""); } + + // PY-14432 + public void testRelativeImportSourceWithSpacesInsideMovedModule() { + doMoveFileTest("pkg/subpkg1/a.py", ""); + } + // PY-14595 public void testNamespacePackageUsedInMovedFunction() { runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() { diff --git a/resources/src/DebuggerSettings.xml b/resources/src/DebuggerSettings.xml index 0fb05d9e667c..e1371944741b 100644 --- a/resources/src/DebuggerSettings.xml +++ b/resources/src/DebuggerSettings.xml @@ -52,6 +52,10 @@