diff --git a/README.md b/README.md index d0527fe4a451..bb90aa7591a1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # IntelliJ IDEA Community Edition ### Building and Running from the IDE -To develop IntelliJ IDEA, you can use either IntelliJ IDEA Community Edition or IntelliJ IDEA Ultimate not older than 14.1.5. To build and run the code: +To develop IntelliJ IDEA, you can use either IntelliJ IDEA Community Edition or IntelliJ IDEA Ultimate not older than 15.0. To build and run the code: * Run **getPlugins.sh** / **getPlugins.bat** from the project root directory to check out additional modules. * If this git repository is not on 'master' branch you need to checkout the same branches/tags in android and android/tools-base git repositories. * Open the project. diff --git a/build/scripts/utils.gant b/build/scripts/utils.gant index 9c288d73d424..2f711c0c46c2 100644 --- a/build/scripts/utils.gant +++ b/build/scripts/utils.gant @@ -796,7 +796,6 @@ private Map readIdeaProperties(Map args) { ideaPropertiesFile.close(); def defaultProperties = ["CVS_PASSFILE": "~/.cvspass", - "JVMVersion": "1.6+", "com.apple.mrj.application.live-resize": "false", "idea.paths.selector": args.system_selector, "idea.executable": args.executable, diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java index a73169ac02ea..cf0786258b34 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/TextWithImportsImpl.java @@ -16,6 +16,7 @@ package com.intellij.debugger.engine.evaluation; import com.intellij.debugger.ui.DebuggerEditorImpl; +import com.intellij.lang.LanguageUtil; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.StdFileTypes; @@ -26,7 +27,6 @@ import com.intellij.psi.*; import com.intellij.xdebugger.XExpression; import com.intellij.xdebugger.evaluation.EvaluationMode; import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl; -import com.intellij.xdebugger.impl.ui.XDebuggerEditorBase; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -136,7 +136,7 @@ public final class TextWithImportsImpl implements TextWithImports{ public static XExpression toXExpression(@Nullable TextWithImports text) { if (text != null && !text.getText().isEmpty()) { return new XExpressionImpl(text.getText(), - XDebuggerEditorBase.getFileTypeLanguage(text.getFileType()), + LanguageUtil.getFileTypeLanguage(text.getFileType()), StringUtil.nullize(text.getImports()), getMode(text.getKind())); } @@ -169,7 +169,7 @@ public final class TextWithImportsImpl implements TextWithImports{ return new TextWithImportsImpl(getKind(expression.getMode()), expression.getExpression(), StringUtil.notNullize(expression.getCustomInfo()), - expression.getLanguage() != null ? expression.getLanguage().getAssociatedFileType() : null); + LanguageUtil.getLanguageFileType(expression.getLanguage())); } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java b/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java index 4dfb02456bbc..50a03a53fd3d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/LocalVariablesUtil.java @@ -494,7 +494,7 @@ public class LocalVariablesUtil { } private static int getTypeSlotSize(PsiType varType) { - if (varType == PsiType.DOUBLE || varType == PsiType.LONG) { + if (PsiType.DOUBLE.equals(varType) || PsiType.LONG.equals(varType)) { return 2; } return 1; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/AlternativeSourceNotificationProvider.java b/java/debugger/impl/src/com/intellij/debugger/ui/AlternativeSourceNotificationProvider.java index 34e42469cd82..1cd8ef71af4a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/AlternativeSourceNotificationProvider.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/AlternativeSourceNotificationProvider.java @@ -18,14 +18,11 @@ package com.intellij.debugger.ui; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.ide.highlighter.JavaClassFileType; +import com.intellij.ide.util.ModuleRendererFactory; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ProjectFileIndex; -import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; @@ -33,6 +30,7 @@ import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.EditorNotificationPanel; import com.intellij.ui.EditorNotifications; +import com.intellij.ui.components.JBList; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.xdebugger.XDebugSession; @@ -41,6 +39,7 @@ import com.intellij.xdebugger.XSourcePosition; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; @@ -115,7 +114,7 @@ public class AlternativeSourceNotificationProvider extends EditorNotifications.P new Function() { @Override public ComboBoxClassElement fun(PsiClass psiClass) { - return new ComboBoxClassElement(psiClass); + return new ComboBoxClassElement((PsiClass)psiClass.getNavigationElement()); } }); @@ -132,27 +131,15 @@ public class AlternativeSourceNotificationProvider extends EditorNotifications.P myClass = aClass; } + private static JList ourDummyList = new JBList(); // to use ModuleRendererFactory + @Override public String toString() { if (myText == null) { - Module module = ModuleUtilCore.findModuleForPsiElement(myClass); - if (module != null) { - myText = module.getName(); - } - else { - VirtualFile virtualFile = myClass.getContainingFile().getVirtualFile(); - final ProjectFileIndex index = ProjectRootManager.getInstance(myClass.getProject()).getFileIndex(); - VirtualFile root = index.getSourceRootForFile(virtualFile); - if (root == null) { - root = index.getClassRootForFile(virtualFile); - } - if (root != null) { - myText = root.getName(); - } - else { - myText = virtualFile.getPath(); - } - } + ModuleRendererFactory factory = ModuleRendererFactory.findInstance(myClass); + DefaultListCellRenderer moduleRenderer = factory.getModuleRenderer(); + moduleRenderer.getListCellRendererComponent(ourDummyList, myClass, 1, false, false); + myText = moduleRenderer.getText(); } return myText; } @@ -174,7 +161,6 @@ public class AlternativeSourceNotificationProvider extends EditorNotifications.P public void actionPerformed(ActionEvent e) { FileEditorManager.getInstance(project).closeFile(file); PsiClass item = ((ComboBoxClassElement)switcher.getSelectedItem()).myClass; - item = (PsiClass)item.getNavigationElement(); // go through compiled DebuggerUtilsEx.setAlternativeSource(file, item.getContainingFile().getVirtualFile()); item.navigate(true); XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); diff --git a/java/execution/impl/src/com/intellij/testIntegration/ShowRecentTests.java b/java/execution/impl/src/com/intellij/testIntegration/ShowRecentTests.java index d590c25befb4..4834b82214bb 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/ShowRecentTests.java +++ b/java/execution/impl/src/com/intellij/testIntegration/ShowRecentTests.java @@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.ListPopupStep; import com.intellij.ui.popup.list.ListPopupImpl; import com.intellij.util.PsiNavigateUtil; +import com.intellij.util.Time; import javax.swing.*; import java.awt.event.ActionEvent; @@ -35,7 +36,7 @@ public class ShowRecentTests extends AnAction { private static final int TEST_LIMIT = Integer.MAX_VALUE; private static Date getSinceDate() { - return new Date(0); + return new Date(System.currentTimeMillis() - Time.DAY); } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java index 612c6c6a9837..dab31757f128 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java @@ -109,7 +109,7 @@ public class SimplifyBooleanExpressionFix extends LocalQuickFixOnPsiElement { public static void simplifyIfStatement(final PsiExpression expression) throws IncorrectOperationException { PsiElement parent = expression.getParent(); if (!(parent instanceof PsiIfStatement) || ((PsiIfStatement)parent).getCondition() != expression) return; - if (!(expression instanceof PsiLiteralExpression) || expression.getType() != PsiType.BOOLEAN) return; + if (!(expression instanceof PsiLiteralExpression) || !PsiType.BOOLEAN.equals(expression.getType())) return; boolean condition = Boolean.parseBoolean(expression.getText()); PsiIfStatement ifStatement = (PsiIfStatement)parent; if (condition) { @@ -210,7 +210,7 @@ public class SimplifyBooleanExpressionFix extends LocalQuickFixOnPsiElement { } public static boolean canBeSimplified(@NotNull PsiExpression expression) { - if (!(expression instanceof PsiConditionalExpression) && expression.getType() != PsiType.BOOLEAN) return false; + if (!(expression instanceof PsiConditionalExpression) && !PsiType.BOOLEAN.equals(expression.getType())) return false; final ExpressionVisitor expressionVisitor = new ExpressionVisitor(expression.getManager(), false); final Ref canBeSimplified = new Ref(Boolean.FALSE); 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 209d0e91634c..6880a6645710 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 @@ -1218,7 +1218,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { } private void generateBoxingUnboxingInstructionFor(@NotNull PsiExpression expression, PsiType expectedType) { - if (expectedType == PsiType.VOID) return; + if (PsiType.VOID.equals(expectedType)) return; PsiType exprType = expression.getType(); 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 aecfbc1e3bca..15e6d6b2e4c0 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 @@ -572,7 +572,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { PsiType returnType = method.getReturnType(); // no warnings in void lambdas, where the expression is not returned anyway - if (block instanceof PsiExpression && block.getParent() instanceof PsiLambdaExpression && returnType == PsiType.VOID) return; + if (block instanceof PsiExpression && block.getParent() instanceof PsiLambdaExpression && PsiType.VOID.equals(returnType)) return; // no warnings for Void methods, where only null can be possibly returned if (returnType == null || returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID)) return; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java index c626a96f8222..38c921825469 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java @@ -36,7 +36,7 @@ public class PurityInference { public static boolean inferPurity(@NotNull final PsiMethod method) { if (!InferenceFromSourceUtil.shouldInferFromSource(method) || - method.getReturnType() == PsiType.VOID || + PsiType.VOID.equals(method.getReturnType()) || method.getBody() == null || method.isConstructor() || PropertyUtil.isSimpleGetter(method)) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index a7894bf8e020..ed52d2c5e78b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -517,18 +517,16 @@ public class StandardInstructionVisitor extends InstructionVisitor { PsiType varType = var.getVariableType(); if (!(varType instanceof PsiPrimitiveType)) return null; - if (varType == PsiType.FLOAT || varType == PsiType.DOUBLE) return null; + if (PsiType.FLOAT.equals(varType) || PsiType.DOUBLE.equals(varType)) return null; - double minValue = varType == PsiType.BYTE ? Byte.MIN_VALUE : - varType == PsiType.SHORT ? Short.MIN_VALUE : - varType == PsiType.INT ? Integer.MIN_VALUE : - varType == PsiType.CHAR ? Character.MIN_VALUE : - Long.MIN_VALUE; - double maxValue = varType == PsiType.BYTE ? Byte.MAX_VALUE : - varType == PsiType.SHORT ? Short.MAX_VALUE : - varType == PsiType.INT ? Integer.MAX_VALUE : - varType == PsiType.CHAR ? Character.MAX_VALUE : - Long.MAX_VALUE; + double minValue = PsiType.BYTE.equals(varType) ? Byte.MIN_VALUE : PsiType.SHORT.equals(varType) + ? Short.MIN_VALUE : PsiType.INT.equals(varType) + ? Integer.MIN_VALUE : PsiType.CHAR.equals(varType) ? Character.MIN_VALUE : + Long.MIN_VALUE; + double maxValue = PsiType.BYTE.equals(varType) ? Byte.MAX_VALUE : PsiType.SHORT.equals(varType) + ? Short.MAX_VALUE : PsiType.INT.equals(varType) + ? Integer.MAX_VALUE : PsiType.CHAR.equals(varType) ? Character.MAX_VALUE : + Long.MAX_VALUE; return checkComparisonWithKnownRange(instruction, runner, memState, opSign, comparedWith, minValue, maxValue); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java index db8e62a1ea52..897eed80e468 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java @@ -105,12 +105,12 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo checkAccessors(field, annotated, project, manager, anno, annoToRemove, holder); - if (REQUIRE_NOTNULL_FIELDS_INITIALIZED) { - checkNotNullFieldsInitialized(field, annotated, manager, holder); - } - checkConstructorParameters(field, annotated, manager, anno, annoToRemove, holder); } + + if (REQUIRE_NOTNULL_FIELDS_INITIALIZED && !annotated.isDeclaredNullable) { + checkNotNullFieldsInitialized(field, manager, holder); + } } @Override @@ -259,17 +259,14 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo LOG.assertTrue(parameter.isPhysical(), setter.getText()); } - private static void checkNotNullFieldsInitialized(PsiField field, - Annotated annotated, - NullableNotNullManager manager, @NotNull ProblemsHolder holder) { - if (annotated.isDeclaredNotNull && !HighlightControlFlowUtil.isFieldInitializedAfterObjectConstruction(field)) { - final PsiAnnotation annotation = AnnotationUtil.findAnnotation(field, manager.getNotNulls()); - if (annotation != null) { - holder.registerProblem(annotation.isPhysical() ? annotation : field.getNameIdentifier(), - "Not-null fields must be initialized", - ProblemHighlightType.GENERIC_ERROR_OR_WARNING); - } - } + private static void checkNotNullFieldsInitialized(PsiField field, NullableNotNullManager manager, @NotNull ProblemsHolder holder) { + PsiAnnotation annotation = manager.getNotNullAnnotation(field, false); + if (annotation == null || HighlightControlFlowUtil.isFieldInitializedAfterObjectConstruction(field)) return; + + boolean byDefault = manager.isContainerAnnotation(annotation); + PsiJavaCodeReferenceElement name = annotation.getNameReferenceElement(); + holder.registerProblem(annotation.isPhysical() && !byDefault ? annotation : field.getNameIdentifier(), + (byDefault && name != null ? "@" + name.getReferenceName() : "Not-null") + " fields must be initialized"); } private void checkConstructorParameters(PsiField field, diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java index ba105015a0f7..3d78588936d4 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java @@ -251,7 +251,7 @@ public class RefJavaUtilImpl extends RefJavaUtil{ if (refExpression instanceof PsiMethodReferenceExpression) { PsiType returnType = psiMethod.getReturnType(); - if (!psiMethod.isConstructor() && returnType != PsiType.VOID) { + if (!psiMethod.isConstructor() && !PsiType.VOID.equals(returnType)) { refMethod.setReturnValueUsed(true); addTypeReference(psiFrom, returnType, refFrom.getRefManager()); } @@ -263,7 +263,7 @@ public class RefJavaUtilImpl extends RefJavaUtil{ ); if (call != null) { PsiType returnType = psiMethod.getReturnType(); - if (!psiMethod.isConstructor() && returnType != PsiType.VOID) { + if (!psiMethod.isConstructor() && !PsiType.VOID.equals(returnType)) { if (!(call.getParent() instanceof PsiExpressionStatement)) { refMethod.setReturnValueUsed(true); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java index efcb53682b63..71016e8d6795 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java @@ -27,11 +27,9 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.WriteExternalException; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.util.*; -import com.intellij.xml.util.XmlUtil; import org.intellij.lang.annotations.Pattern; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -407,7 +405,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe if (psiElement instanceof PsiMethod) { final PsiMethod method = (PsiMethod)psiElement; final PsiType returnType = method.getReturnType(); - if (returnType != null && returnType != PsiType.VOID) { + if (returnType != null && !PsiType.VOID.equals(returnType)) { final PsiExpression returnValue = statement.getReturnValue(); if (returnValue != null) { final PsiType valueType = returnValue.getType(); diff --git a/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java b/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java index 29c0f5806a8c..50a5e91903d0 100644 --- a/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java +++ b/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java @@ -221,7 +221,7 @@ public class ParametersFolder { if (expression == null) break; final PsiType expressionType = ((PsiExpression)expression).getType(); - if (expressionType != null && expressionType != PsiType.VOID && !(expression.getParent() instanceof PsiExpressionStatement)) { + if (expressionType != null && !PsiType.VOID.equals(expressionType) && !(expression.getParent() instanceof PsiExpressionStatement)) { if (dependsOnLocals(expression, inputVariables)) { break; } diff --git a/java/java-impl/src/com/intellij/codeInsight/FunctionalInterfaceSuggester.java b/java/java-impl/src/com/intellij/codeInsight/FunctionalInterfaceSuggester.java index c9373869f9ea..edde071f1ef4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/FunctionalInterfaceSuggester.java +++ b/java/java-impl/src/com/intellij/codeInsight/FunctionalInterfaceSuggester.java @@ -123,7 +123,7 @@ public class FunctionalInterfaceSuggester { return null; } - if (returnType == PsiType.VOID && interfaceMethodReturnType != PsiType.VOID) { + if (PsiType.VOID.equals(returnType) && !PsiType.VOID.equals(interfaceMethodReturnType)) { return null; } diff --git a/java/java-impl/src/com/intellij/codeInsight/JavaRegExpModifierProvider.java b/java/java-impl/src/com/intellij/codeInsight/JavaRegExpModifierProvider.java index 3c31a01506a0..261b1998fa78 100644 --- a/java/java-impl/src/com/intellij/codeInsight/JavaRegExpModifierProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/JavaRegExpModifierProvider.java @@ -30,7 +30,7 @@ public class JavaRegExpModifierProvider implements RegExpModifierProvider { @Override public int getFlags(PsiElement elementInHost, PsiFile regexp) { final PsiExpressionList list = PsiTreeUtil.getParentOfType(elementInHost, PsiExpressionList.class); - if (list != null && list.getExpressions().length == 2 && list.getExpressionTypes()[1] == PsiType.INT) { + if (list != null && list.getExpressions().length == 2 && PsiType.INT.equals(list.getExpressionTypes()[1])) { final Object result = JavaConstantExpressionEvaluator.computeConstantExpression(list.getExpressions()[1], false); if (result instanceof Integer) { //noinspection MagicConstant diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index dc12d45ad3fe..44cfd529b335 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -757,7 +757,7 @@ public class JavaCompletionUtil { TailType toInsert = tailType; LookupItem lookupItem = item.as(LookupItem.CLASS_CONDITION_KEY); if (lookupItem == null || lookupItem.getAttribute(LookupItem.TAIL_TYPE_ATTR) != TailType.UNKNOWN) { - if (!hasTail && item.getObject() instanceof PsiMethod && ((PsiMethod)item.getObject()).getReturnType() == PsiType.VOID) { + if (!hasTail && item.getObject() instanceof PsiMethod && PsiType.VOID.equals(((PsiMethod)item.getObject()).getReturnType())) { PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments(); if (psiElement().beforeLeaf(psiElement().withText(".")).accepts(context.getFile().findElementAt(context.getTailOffset() - 1))) { return false; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java index 74745435d576..cceb1668a231 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java @@ -221,19 +221,26 @@ public class JavaInheritorsGetter extends CompletionProvider expectedClassTypes, final PrefixMatcher matcher, final Consumer consumer) { + processInheritors(parameters.getOriginalFile(), parameters.getPosition(), expectedClassTypes, matcher, consumer); + } + + public static void processInheritors(final PsiFile file, + final PsiElement context, + final Collection expectedClassTypes, + final PrefixMatcher matcher, final Consumer consumer) { //quick - if (!processMostProbableInheritors(parameters, expectedClassTypes, consumer)) return; + if (!processMostProbableInheritors(file, context, expectedClassTypes, consumer)) return; //long for (final PsiClassType type : expectedClassTypes) { - CodeInsightUtil.processSubTypes(type, parameters.getPosition(), false, matcher, consumer); + CodeInsightUtil.processSubTypes(type, context, false, matcher, consumer); } } - private static boolean processMostProbableInheritors(CompletionParameters parameters, + private static boolean processMostProbableInheritors(PsiFile contextFile, + PsiElement context, Collection expectedClassTypes, Consumer consumer) { - PsiFile file = parameters.getOriginalFile(); for (final PsiClassType type : expectedClassTypes) { consumer.consume(type); @@ -243,15 +250,15 @@ public class JavaInheritorsGetter extends CompletionProvider processor = CodeInsightUtil.createInheritorsProcessor(parameters.getPosition(), type, 0, false, + final Processor processor = CodeInsightUtil.createInheritorsProcessor(context, type, 0, false, consumer, baseClass, baseSubstitutor); final StatisticsInfo[] stats = StatisticsManager.getInstance().getAllValues(JavaStatisticsManager.getAfterNewKey(type)); for (final StatisticsInfo statisticsInfo : stats) { final String value = statisticsInfo.getValue(); if (value.startsWith(JavaStatisticsManager.CLASS_PREFIX)) { final String qname = value.substring(JavaStatisticsManager.CLASS_PREFIX.length()); - final PsiClass psiClass = JavaPsiFacade.getInstance(file.getProject()).findClass(qname, file.getResolveScope()); - if (psiClass != null && !PsiTreeUtil.isAncestor(file, psiClass, true) && !processor.process(psiClass)) break; + final PsiClass psiClass = JavaPsiFacade.getInstance(contextFile.getProject()).findClass(qname, contextFile.getResolveScope()); + if (psiClass != null && !PsiTreeUtil.isAncestor(contextFile, psiClass, true) && !processor.process(psiClass)) break; } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java index 969dfdbcd6b7..e9d17e28612e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java @@ -491,7 +491,7 @@ public class JavaKeywordCompletion { private static boolean mayExpectBoolean(CompletionParameters parameters) { for (ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { PsiType type = info.getType(); - if (type instanceof PsiClassType || type == PsiType.BOOLEAN) return true; + if (type instanceof PsiClassType || PsiType.BOOLEAN.equals(type)) return true; } return false; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java index 5908a230a32d..a763fb55b630 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMemberNameCompletionContributor.java @@ -325,7 +325,7 @@ public class JavaMemberNameCompletionContributor extends CompletionContributor { } } - if (!hasStartMatches(matcher, result) && PsiType.VOID != varType && includeOverlapped) { + if (!hasStartMatches(matcher, result) && !PsiType.VOID.equals(varType) && includeOverlapped) { // use suggested names as suffixes final String requiredSuffix = codeStyleManager.getSuffixByVariableKind(varKind); final String prefix = matcher.getPrefix(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodMergingContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodMergingContributor.java index c9e8ae1f78db..98029f6bcd2a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodMergingContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodMergingContributor.java @@ -81,7 +81,7 @@ public class JavaMethodMergingContributor extends CompletionContributor { private static int getPriority(LookupElement element) { PsiMethod method = assertNotNull(getItemMethod(element)); - return (method.getReturnType() == PsiType.VOID ? 0 : 1) + + return (PsiType.VOID.equals(method.getReturnType()) ? 0 : 1) + (method.getParameterList().getParametersCount() > 0 ? 2 : 0); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index d181a34e6358..85d45e784f15 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -85,12 +85,6 @@ public class JavaSmartCompletionContributor extends CompletionContributor { return THROWABLES_FILTER; } - //throws list - PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class); - if (method != null && PsiTreeUtil.isAncestor(method.getThrowsList(), element, true)) { - return THROWABLES_FILTER; - } - //new xxx.yyy if (psiElement().afterLeaf(psiElement().withText(".")).withSuperParent(2, psiElement(PsiNewExpression.class)).accepts(element)) { if (((PsiNewExpression)element.getParent().getParent()).getClassReference() == element.getParent()) { @@ -107,6 +101,10 @@ public class JavaSmartCompletionContributor extends CompletionContributor { return null; } + private static boolean isInsideThrowsList(PsiElement element) { + PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class); + return method != null && PsiTreeUtil.isAncestor(method.getThrowsList(), element, true); + } public JavaSmartCompletionContributor() { @@ -128,11 +126,18 @@ public class JavaSmartCompletionContributor extends CompletionContributor { PsiTreeUtil.findElementOfClassAtOffset(element.getContainingFile(), parameters.getOffset(), PsiJavaCodeReferenceElement.class, false); if (reference != null) { ElementFilter filter = getClassReferenceFilter(element); + boolean completeConstructor = filter != null; + if (filter == null && isInsideThrowsList(element)) { + filter = THROWABLES_FILTER; + } if (filter != null) { final List infos = Arrays.asList(getExpectedTypes(parameters)); - for (final LookupElement item : completeReference(element, reference, filter, true, false, parameters, result.getPrefixMatcher())) { + for (LookupElement item : completeReference(element, reference, filter, true, false, parameters, result.getPrefixMatcher())) { if (item.getObject() instanceof PsiClass) { - result.addElement(decorate(LookupElementDecorator.withInsertHandler(item, ConstructorInsertHandler.SMART_INSTANCE), infos)); + if (completeConstructor) { + item = LookupElementDecorator.withInsertHandler(item, ConstructorInsertHandler.SMART_INSTANCE); + } + result.addElement(decorate(item, infos)); } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java index 5ac5057d8113..31de612c9ad3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java @@ -74,7 +74,7 @@ class SmartCastProvider extends CompletionProvider { type = ((PsiWildcardType)type).getBound(); } - if (type == null || type == PsiType.VOID) { + if (type == null || PsiType.VOID.equals(type)) { continue; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddVariableInitializerFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddVariableInitializerFix.java index b1736eb96eb1..1c69fae07625 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddVariableInitializerFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddVariableInitializerFix.java @@ -16,18 +16,33 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInsight.completion.*; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.lookup.*; +import com.intellij.codeInsight.template.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTypesUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.util.RefactoringUtil; +import com.intellij.util.Consumer; +import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import static com.intellij.util.containers.ContainerUtil.*; public class AddVariableInitializerFix implements IntentionAction { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.AddReturnFix"); @@ -62,9 +77,10 @@ public class AddVariableInitializerFix implements IntentionAction { public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { if (!FileModificationService.getInstance().prepareFileForWrite(myVariable.getContainingFile())) return; - String initializerText = suggestInitializer(); - PsiElementFactory factory = JavaPsiFacade.getInstance(myVariable.getProject()).getElementFactory(); - PsiExpression initializer = factory.createExpressionFromText(initializerText, myVariable); + final LookupElement[] suggestedInitializers = suggestInitializer(myVariable); + LOG.assertTrue(suggestedInitializers.length > 0); + LOG.assertTrue(suggestedInitializers[0] instanceof ExpressionLookupItem); + final PsiExpression initializer = (PsiExpression) suggestedInitializers[0].getObject(); if (myVariable instanceof PsiLocalVariable) { ((PsiLocalVariable)myVariable).setInitializer(initializer); } @@ -74,17 +90,120 @@ public class AddVariableInitializerFix implements IntentionAction { else { LOG.error("Unknown variable type: "+myVariable); } - PsiVariable var = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(myVariable); - TextRange range = var.getInitializer().getTextRange(); - int offset = range.getStartOffset(); - editor.getCaretModel().moveToOffset(offset); - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - editor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset()); + runAssignmentTemplate(Collections.singletonList(myVariable.getInitializer()), suggestedInitializers, editor); } - private String suggestInitializer() { - PsiType type = myVariable.getType(); - return PsiTypesUtil.getDefaultValueOfType(type); + public static void runAssignmentTemplate(@NotNull final List initializers, + @NotNull final LookupElement[] suggestedInitializers, + @Nullable Editor editor) { + if (editor == null) return; + LOG.assertTrue(!initializers.isEmpty()); + final PsiExpression initializer = ContainerUtil.getFirstItem(initializers); + PsiElement context = initializers.size() == 1 ? initializer : PsiTreeUtil.findCommonParent(initializers); + PsiDocumentManager.getInstance(initializer.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument()); + final TemplateBuilderImpl builder = (TemplateBuilderImpl)TemplateBuilderFactory.getInstance().createTemplateBuilder(context); + for (PsiExpression e : initializers) { + builder.replaceElement(e, new Expression() { + @Nullable + @Override + public Result calculateResult(ExpressionContext context1) { + return calculateQuickResult(context1); + } + + @Nullable + @Override + public Result calculateQuickResult(ExpressionContext context1) { + return new PsiElementResult(suggestedInitializers[0].getPsiElement()); + } + + @Nullable + @Override + public LookupElement[] calculateLookupItems(ExpressionContext context1) { + return suggestedInitializers; + } + }); + } + builder.run(editor, false); + } + + @NotNull + public static LookupElement[] suggestInitializer(final PsiVariable variable) { + PsiType type = variable.getType(); + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(variable.getProject()); + if (type instanceof PsiClassType) { + final PsiClass aClass = PsiTypesUtil.getPsiClass(type); + if (aClass != null) { + final LookupElement nullLookupItem = new ExpressionLookupItem(elementFactory.createExpressionFromText(PsiKeyword.NULL, variable)); + if (InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_LANG_ITERABLE) || + InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_MAP)) { + final List suggestedTypes = new SmartList(); + JavaInheritorsGetter.processInheritors(variable.getContainingFile(), variable, Collections.singleton((PsiClassType) type), PrefixMatcher.ALWAYS_TRUE, new Consumer() { + @Override + public void consume(PsiType type) { + LOG.assertTrue(type instanceof PsiClassType); + final PsiClass psiClass = PsiTypesUtil.getPsiClass(type); + if (psiClass != null && + !psiClass.isInterface() && + !psiClass.hasModifierProperty(PsiModifier.ABSTRACT) && + psiClass.hasModifierProperty(PsiModifier.PUBLIC) && + PsiUtil.hasDefaultConstructor(psiClass)) { + suggestedTypes.add(type); + } + } + }); + + List sortedLookups = map(sorted(map(suggestedTypes, new Function() { + @Override + public LookupElement fun(PsiType type) { + return PsiTypeLookupItem.createLookupItem(type, variable); + } + }), new Comparator() { + @Override + public int compare(LookupElement o1, LookupElement o2) { + final int count1 = StatisticsWeigher.getBaseStatisticsInfo(o1, null).getUseCount(); + final int count2 = StatisticsWeigher.getBaseStatisticsInfo(o2, null).getUseCount(); + return count2 - count1; + } + }), new Function() { + @Override + public LookupElement fun(LookupElement element) { + final LookupElementDecorator constructorLookupElement = + LookupElementDecorator.withInsertHandler(element, ConstructorInsertHandler.BASIC_INSTANCE); + return new LookupElementDecorator(constructorLookupElement) { + @Override + public void renderElement(LookupElementPresentation presentation) { + super.renderElement(presentation); + presentation.setTailText(""); + presentation.setItemText(PsiKeyword.NEW + " " + presentation.getItemText() + "()"); + } + + @Override + public void handleInsert(InsertionContext context) { + super.handleInsert(context); + context.getDocument().insertString(context.getStartOffset(), PsiKeyword.NEW + " "); + } + }; + } + }); + LookupElement[] result = new LookupElement[sortedLookups.size() + 1]; + result[0] = nullLookupItem; + for (int i = 0; i < sortedLookups.size(); i++) { + LookupElement lookup = sortedLookups.get(i); + result[i + 1] = lookup; + } + return result; + } else { + if (PsiUtil.hasDefaultConstructor(aClass)) { + final PsiExpression newExpression = elementFactory + .createExpressionFromText(PsiKeyword.NEW + " " + type.getCanonicalText(false) + "()", variable); + return new LookupElement[]{nullLookupItem, new ExpressionLookupItem(newExpression)}; + } + } + } + } + final String defaultValue = PsiTypesUtil.getDefaultValueOfType(type); + final PsiExpression expression = elementFactory.createExpressionFromText(defaultValue, variable); + return new LookupElement[] {new ExpressionLookupItem(expression)}; } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DelegateWithDefaultParamValueIntentionAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DelegateWithDefaultParamValueIntentionAction.java index fdec4a6b1910..a4b4a0965b36 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DelegateWithDefaultParamValueIntentionAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DelegateWithDefaultParamValueIntentionAction.java @@ -145,7 +145,7 @@ public class DelegateWithDefaultParamValueIntentionAction extends PsiElementBase final String methodCall; if (method.getReturnType() == null) { methodCall = "this"; - } else if (method.getReturnType() != PsiType.VOID) { + } else if (!PsiType.VOID.equals(method.getReturnType())) { methodCall = "return " + method.getName(); } else { methodCall = method.getName(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/InitializeFinalFieldInConstructorFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/InitializeFinalFieldInConstructorFix.java index ea5e3641cb34..d59fd0ddd6d5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/InitializeFinalFieldInConstructorFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/InitializeFinalFieldInConstructorFix.java @@ -15,23 +15,20 @@ */ package com.intellij.codeInsight.daemon.impl.quickfix; -import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInsight.generation.PsiMethodMember; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.ide.util.MemberChooser; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -93,59 +90,34 @@ public class InitializeFinalFieldInConstructorFix implements IntentionAction { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - final List statements = addFieldInitialization(constructors, myField, project); - final PsiExpressionStatement highestStatement = getHighestElement(statements); - if (highestStatement == null) return; - - final PsiAssignmentExpression expression = (PsiAssignmentExpression)highestStatement.getExpression(); - final PsiElement rightExpression = expression.getRExpression(); - - final TextRange expressionRange = rightExpression.getTextRange(); - editor.getCaretModel().moveToOffset(expressionRange.getStartOffset()); - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - editor.getSelectionModel().setSelection(expressionRange.getStartOffset(), expressionRange.getEndOffset()); + addFieldInitialization(constructors, myField, project, editor); } }); } - @Nullable - private static T getHighestElement(@NotNull List elements) { - T highest = null; - int highestTextOffset = Integer.MAX_VALUE; - for (T element : elements) { - final T forcedElem = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(element); - final int startOffset = forcedElem.getTextOffset(); - if (startOffset < highestTextOffset) { - highest = forcedElem; - highestTextOffset = startOffset; - } - } - return highest; - } + private static void addFieldInitialization(@NotNull List constructors, + @NotNull PsiField field, + @NotNull Project project, + @Nullable Editor editor) { + final List rExpressions = new ArrayList(constructors.size()); + final LookupElement[] suggestedInitializers = AddVariableInitializerFix.suggestInitializer(field); - @NotNull - private static List addFieldInitialization(@NotNull List constructors, - @NotNull PsiField field, - @NotNull Project project) { - final List statements = new ArrayList(); for (PsiMethod constructor : constructors) { - final PsiExpressionStatement statement = addFieldInitialization(constructor, field, project); - if (statement != null) { - statements.add(statement); - } + rExpressions.add(addFieldInitialization(constructor, suggestedInitializers, field, project)); } - return statements; + AddVariableInitializerFix.runAssignmentTemplate(rExpressions, suggestedInitializers, editor); } @Nullable - private static PsiExpressionStatement addFieldInitialization(@NotNull PsiMethod constructor, - @NotNull PsiField field, - @NotNull Project project) { + private static PsiExpression addFieldInitialization(@NotNull PsiMethod constructor, + @NotNull LookupElement[] suggestedInitializers, + @NotNull PsiField field, + @NotNull Project project) { PsiCodeBlock methodBody = constructor.getBody(); if (methodBody == null) return null; final String fieldName = field.getName(); - String stmtText = fieldName + " = " + suggestInitValue(field) + ";"; + String stmtText = fieldName + " = " + suggestedInitializers[0].getPsiElement().getText() + ";"; if (methodContainsParameterWithName(constructor, fieldName)) { stmtText = "this." + stmtText; } @@ -154,7 +126,9 @@ public class InitializeFinalFieldInConstructorFix implements IntentionAction { final PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory(); final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); - return (PsiExpressionStatement)methodBody.add(codeStyleManager.reformat(factory.createStatementFromText(stmtText, methodBody))); + final PsiExpressionStatement addedStatement = (PsiExpressionStatement)methodBody.add(codeStyleManager + .reformat(factory.createStatementFromText(stmtText, methodBody))); + return ((PsiAssignmentExpression)addedStatement.getExpression()).getRExpression(); } private static boolean methodContainsParameterWithName(@NotNull PsiMethod constructor, @NotNull String name) { @@ -228,11 +202,6 @@ public class InitializeFinalFieldInConstructorFix implements IntentionAction { return result.toArray(new PsiMethod[result.size()]); } - private static String suggestInitValue(@NotNull PsiField field) { - PsiType type = field.getType(); - return PsiTypesUtil.getDefaultValueOfType(type); - } - @Override public boolean startInWriteAction() { return false; diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingReturnExpressionFixer.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingReturnExpressionFixer.java index eb68dd4979f7..cf236a6e3503 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingReturnExpressionFixer.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingReturnExpressionFixer.java @@ -55,7 +55,7 @@ public class MissingReturnExpressionFixer implements Fixer { PsiElement parent = PsiTreeUtil.getParentOfType(psiElement, PsiClassInitializer.class, PsiMethod.class); if (parent instanceof PsiMethod) { final PsiType returnType = ((PsiMethod)parent).getReturnType(); - if (returnType != null && returnType != PsiType.VOID) { + if (returnType != null && !PsiType.VOID.equals(returnType)) { final int startOffset = retStatement.getTextRange().getStartOffset(); if (returnValue != null) { editor.getDocument().insertString(startOffset + "return".length(), ";"); @@ -84,7 +84,7 @@ public class MissingReturnExpressionFixer implements Fixer { if (!(prev instanceof PsiJavaToken)) { int offset = returnStatement.getTextRange().getEndOffset(); final PsiMethod method = PsiTreeUtil.getParentOfType(returnStatement, PsiMethod.class, true, PsiLambdaExpression.class); - if (method != null && method.getReturnType() == PsiType.VOID) { + if (method != null && PsiType.VOID.equals(method.getReturnType())) { offset = returnStatement.getTextRange().getStartOffset() + "return".length(); } editor.getDocument().insertString(offset, ";"); @@ -101,7 +101,7 @@ public class MissingReturnExpressionFixer implements Fixer { editor.getDocument().insertString(offset, ";"); if (prevToken.getTokenType() == JavaTokenType.RETURN_KEYWORD) { final PsiMethod method = PsiTreeUtil.getParentOfType(returnStatement, PsiMethod.class); - if (method != null && method.getReturnType() != PsiType.VOID) { + if (method != null && !PsiType.VOID.equals(method.getReturnType())) { editor.getCaretModel().moveToOffset(offset); processor.setSkipEnter(true); } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java index 9ec8d1a32f84..ce293e217f74 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java @@ -115,7 +115,7 @@ public class GenerateDelegateHandler implements LanguageCodeInsightActionHandler PsiModifierList modifierList = null; - if (method.getReturnType() != PsiType.VOID) { + if (!PsiType.VOID.equals(method.getReturnType())) { call.append("return "); } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java index 291003c3f460..7756b0725055 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java @@ -337,7 +337,7 @@ public class OverrideImplementUtil extends OverrideImplementExploreUtil { @NotNull public static String callSuper(PsiMethod superMethod, PsiMethod overriding) { @NonNls StringBuilder buffer = new StringBuilder(); - if (!superMethod.isConstructor() && superMethod.getReturnType() != PsiType.VOID) { + if (!superMethod.isConstructor() && !PsiType.VOID.equals(superMethod.getReturnType())) { buffer.append("return "); } buffer.append("super"); diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/IntroduceVariableIntentionAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/IntroduceVariableIntentionAction.java index 2324cb2b6838..e45643fa52fb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/IntroduceVariableIntentionAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/IntroduceVariableIntentionAction.java @@ -54,7 +54,7 @@ public class IntroduceVariableIntentionAction extends BaseRefactoringIntentionAc final PsiExpression expression = statement.getExpression(); - return expression.getType() != PsiType.VOID && !(expression instanceof PsiAssignmentExpression); + return !PsiType.VOID.equals(expression.getType()) && !(expression instanceof PsiAssignmentExpression); } @Override diff --git a/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java b/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java index 9d526d3d1aa2..dbfba1464c4c 100644 --- a/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java +++ b/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java @@ -406,7 +406,7 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement if (typeParameterList != null) { createTypeParamsListComment(builder, project, commenter, typeParameterList); } - if (psiMethod.getReturnType() != null && psiMethod.getReturnType() != PsiType.VOID) { + if (psiMethod.getReturnType() != null && !PsiType.VOID.equals(psiMethod.getReturnType())) { builder.append(CodeDocumentationUtil.createDocCommentLine(RETURN_TAG, project, commenter)); builder.append(LINE_SEPARATOR); } diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java index 3cf8da2f8fb1..0797d6797949 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java @@ -41,6 +41,7 @@ import com.intellij.refactoring.util.*; import com.intellij.refactoring.util.usageInfo.DefaultConstructorImplicitUsageInfo; import com.intellij.refactoring.util.usageInfo.NoConstructorClassUsageInfo; import com.intellij.usageView.UsageInfo; +import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.ContainerUtil; @@ -857,13 +858,13 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr public boolean value(Pair pair) { final PsiParameter parameter = pair.first; final String oldParamName = pair.second; - final int idx = Arrays.binarySearch(oldParameterNames, oldParamName); + final int idx = ArrayUtil.find(oldParameterNames, oldParamName); return idx >= 0 && idx == method.getParameterList().getParameterIndex(parameter) && changeInfo.getNewParameters()[idx].getOldIndex() == idx; } }, new Condition() { @Override public boolean value(String paramName) { - return Arrays.binarySearch(oldParameterNames, paramName) >= 0; + return ArrayUtil.find(oldParameterNames, paramName) >= 0; } }); } 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 23b0a7bfef69..570d4d57f563 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -267,10 +267,10 @@ public class ExtractMethodProcessor implements MatchProvider { if (expressionType == null) { expressionType = PsiType.VOID; } - myHasExpressionOutput = expressionType != PsiType.VOID; + myHasExpressionOutput = !PsiType.VOID.equals(expressionType); final PsiType returnStatementType = getExpectedReturnType(); - myHasReturnStatementOutput = myHasReturnStatement && returnStatementType != null && returnStatementType != PsiType.VOID; + myHasReturnStatementOutput = myHasReturnStatement && returnStatementType != null && !PsiType.VOID.equals(returnStatementType); if (myGenerateConditionalExit && myOutputVariables.length == 1) { if (!(myOutputVariables[0].getType() instanceof PsiPrimitiveType)) { @@ -381,7 +381,7 @@ public class ExtractMethodProcessor implements MatchProvider { private boolean areAllExitPointsAreNotNull(PsiType returnStatementType) { if (insertNotNullCheckIfPossible() && myControlFlowWrapper.getOutputVariables(false).length == 0) { - boolean isNotNull = returnStatementType != null && returnStatementType != PsiType.VOID; + boolean isNotNull = returnStatementType != null && !PsiType.VOID.equals(returnStatementType); for (PsiStatement statement : myExitStatements) { if (statement instanceof PsiReturnStatement) { final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue(); @@ -432,7 +432,7 @@ public class ExtractMethodProcessor implements MatchProvider { return; } final PsiMethod method = (PsiMethod)myCodeFragmentMember; - if (!method.isConstructor() || myReturnType != PsiType.VOID) { + if (!method.isConstructor() || !PsiType.VOID.equals(myReturnType)) { return; } final PsiCodeBlock body = method.getBody(); diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java index f7686c8ad021..18beeac7a658 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java @@ -277,7 +277,7 @@ public class ExtractLightMethodObjectHandler { private static boolean isValidVariableType(PsiType type) { if (type instanceof PsiClassType || type instanceof PsiArrayType || - type instanceof PsiPrimitiveType && type != PsiType.VOID) { + type instanceof PsiPrimitiveType && !PsiType.VOID.equals(type)) { return true; } return false; diff --git a/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java b/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java index c3d9cffb8638..22c8fd78f9db 100644 --- a/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationProcessor.java @@ -549,7 +549,7 @@ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor { @NonNls final StringBuffer buffer = new StringBuffer(); buffer.append("{\n"); - if (methodToAdd.getReturnType() != PsiType.VOID) { + if (!PsiType.VOID.equals(methodToAdd.getReturnType())) { buffer.append("return "); } diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java index ba9a4918a330..b2c82e29a2bb 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java @@ -747,7 +747,7 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor { PsiType returnType = callSubstitutor.substitute(myMethod.getReturnType()); String resultName = null; final int applicabilityLevel = PsiUtil.getApplicabilityLevel(myMethod, callSubstitutor, argumentList); - if (returnType != null && returnType != PsiType.VOID && tailCallType == InlineUtil.TailCallType.None) { + if (returnType != null && !PsiType.VOID.equals(returnType) && tailCallType == InlineUtil.TailCallType.None) { resultName = myJavaCodeStyle.propertyNameToVariableName("result", VariableKind.LOCAL_VARIABLE); resultName = myJavaCodeStyle.suggestUniqueVariableName(resultName, block.getFirstChild(), true); PsiDeclarationStatement declaration = myFactory.createVariableDeclarationStatement(resultName, returnType, null); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index b46589f451d6..e401a679f87d 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -236,7 +236,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { PsiExpression expression = PsiTreeUtil.getParentOfType(elementAtCaret, PsiExpression.class); while (expression != null) { if (!expressions.contains(expression) && !(expression instanceof PsiParenthesizedExpression) && !(expression instanceof PsiSuperExpression) && - (acceptVoid || expression.getType() != PsiType.VOID)) { + (acceptVoid || !PsiType.VOID.equals(expression.getType()))) { if (expression instanceof PsiMethodReferenceExpression) { expressions.add(expression); } diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java index 59dbd1ab271f..742f955d6dbf 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java @@ -179,14 +179,15 @@ public class MoveJavaMemberHandler implements MoveMemberHandler { changeQualifier(refExpr, usage.qualifierClass, usage.member); } else { - final PsiReferenceParameterList parameterList = refExpr.getParameterList(); - if (parameterList != null && parameterList.getTypeArguments().length == 0 && !(refExpr instanceof PsiMethodReferenceExpression)){ - refExpr.setQualifierExpression(null); - } else { - final Project project = element.getProject(); - final PsiClass targetClass = - JavaPsiFacade.getInstance(project).findClass(options.getTargetClassName(), GlobalSearchScope.projectScope(project)); - if (targetClass != null) { + final Project project = element.getProject(); + final PsiClass targetClass = + JavaPsiFacade.getInstance(project).findClass(options.getTargetClassName(), GlobalSearchScope.projectScope(project)); + if (targetClass != null) { + final PsiReferenceParameterList parameterList = refExpr.getParameterList(); + if ((targetClass.isEnum() || PsiTreeUtil.isAncestor(targetClass, element, true)) && parameterList != null && parameterList.getTypeArguments().length == 0 && !(refExpr instanceof PsiMethodReferenceExpression)) { + refExpr.setQualifierExpression(null); + } + else { changeQualifier(refExpr, targetClass, usage.member); } } diff --git a/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueAction.java b/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueAction.java index 026fa135fdb3..741bf6dd82aa 100644 --- a/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueAction.java +++ b/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueAction.java @@ -38,7 +38,7 @@ public class WrapReturnValueAction extends BaseRefactoringAction{ final PsiMethod psiMethod = PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); if (psiMethod != null && !(psiMethod instanceof PsiCompiledElement)) { final PsiType returnType = psiMethod.getReturnType(); - return returnType != null && returnType != PsiType.VOID; + return returnType != null && !PsiType.VOID.equals(returnType); } return false; } diff --git a/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java b/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java index 0dc68c326dac..a0cc2fa7fea5 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java +++ b/java/java-impl/src/com/intellij/slicer/SliceUsageCellRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiFormatUtil; import com.intellij.psi.util.PsiFormatUtilBase; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.ui.JBColor; import com.intellij.ui.SimpleTextAttributes; import com.intellij.usages.TextChunk; import com.intellij.util.FontUtil; @@ -56,7 +57,7 @@ public class SliceUsageCellRenderer extends SliceUsageCellRendererBase { TextChunk textChunk = text[i]; SimpleTextAttributes attributes = textChunk.getSimpleAttributesIgnoreBackground(); if (isForcedLeaf) { - attributes = attributes.derive(attributes.getStyle(), Color.LIGHT_GRAY, attributes.getBgColor(), attributes.getWaveColor()); + attributes = attributes.derive(attributes.getStyle(), JBColor.LIGHT_GRAY, attributes.getBgColor(), attributes.getWaveColor()); } boolean inUsage = (attributes.getFontStyle() & Font.BOLD) != 0; if (isInsideContainer && inUsage) { @@ -66,7 +67,7 @@ public class SliceUsageCellRenderer extends SliceUsageCellRendererBase { //setPaintFocusBorder(true); } append(textChunk.getText(), attributes); - if(i == 0){ + if (i == 0) { append(FontUtil.spaceAndThinSpace()); } } diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index d27e56a370a2..c602395895c2 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -132,7 +132,7 @@ public class LambdaUtil { public static boolean isLambdaFullyInferred(PsiLambdaExpression expression, PsiType functionalInterfaceType) { final boolean hasParams = expression.getParameterList().getParametersCount() > 0; - if (hasParams || getFunctionalInterfaceReturnType(functionalInterfaceType) != PsiType.VOID) { //todo check that void lambdas without params check + if (hasParams || !PsiType.VOID.equals(getFunctionalInterfaceReturnType(functionalInterfaceType))) { //todo check that void lambdas without params check return !dependsOnTypeParams(functionalInterfaceType, functionalInterfaceType, expression); } @@ -570,7 +570,7 @@ public class LambdaUtil { } public static String checkReturnTypeCompatible(PsiLambdaExpression lambdaExpression, PsiType functionalInterfaceReturnType) { - if (functionalInterfaceReturnType == PsiType.VOID) { + if (PsiType.VOID.equals(functionalInterfaceReturnType)) { final PsiElement body = lambdaExpression.getBody(); if (body instanceof PsiCodeBlock) { if (!getReturnExpressions(lambdaExpression).isEmpty()) return "Unexpected return value"; diff --git a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java index f590c38392d6..3eec614acb26 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java @@ -32,7 +32,7 @@ import java.util.*; public class PsiIntersectionType extends PsiType.Stub { private final PsiType[] myConjuncts; - private PsiIntersectionType(@NotNull PsiType[] conjuncts) { + protected PsiIntersectionType(@NotNull PsiType[] conjuncts) { super(PsiAnnotation.EMPTY_ARRAY); myConjuncts = conjuncts; } @@ -67,7 +67,7 @@ public class PsiIntersectionType extends PsiType.Stub { } } - private static Set flatten(PsiType[] conjuncts, Set types) { + protected static Set flatten(PsiType[] conjuncts, Set types) { for (PsiType conjunct : conjuncts) { if (conjunct instanceof PsiIntersectionType) { PsiIntersectionType type = (PsiIntersectionType)conjunct; diff --git a/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java b/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java index 6736b8581a22..7b73a8839259 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java @@ -321,7 +321,7 @@ public class PsiMethodReferenceUtil { returnType = ((PsiMethod)resolve).getReturnType(); } PsiType methodReturnType = subst.substitute(returnType); - if (interfaceReturnType != null && interfaceReturnType != PsiType.VOID) { + if (interfaceReturnType != null && !PsiType.VOID.equals(interfaceReturnType)) { if (methodReturnType == null) { methodReturnType = JavaPsiFacade.getElementFactory(expression.getProject()).createType(containingClass, subst); } diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiClassUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiClassUtil.java index 745b9bae07c5..1f2d47996384 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiClassUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiClassUtil.java @@ -33,7 +33,11 @@ public class PsiClassUtil { public static boolean isRunnableClass(final PsiClass aClass, final boolean mustBePublic, boolean mustNotBeAbstract) { if (aClass instanceof PsiAnonymousClass) return false; if (aClass.isInterface()) return false; - if (mustBePublic && !aClass.hasModifierProperty(PsiModifier.PUBLIC)) return false; + if (mustBePublic && !aClass.hasModifierProperty(PsiModifier.PUBLIC)) { + if (mustNotBeAbstract || !aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return false; + } + } if (aClass.hasModifierProperty(PsiModifier.PRIVATE)) return false; if (mustNotBeAbstract && aClass.hasModifierProperty(PsiModifier.ABSTRACT)) return false; return aClass.getContainingClass() == null || aClass.hasModifierProperty(PsiModifier.STATIC); diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiConcatenationUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiConcatenationUtil.java index 70c97495995b..1704fea347fd 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiConcatenationUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiConcatenationUtil.java @@ -66,7 +66,7 @@ public class PsiConcatenationUtil { addFormatParameter(subExpression, formatString, formatParameters, printfFormat); } if (stringStarted) { - if (optype != null && (optype.equalsToText(JAVA_LANG_STRING) || optype == PsiType.CHAR)) { + if (optype != null && (optype.equalsToText(JAVA_LANG_STRING) || PsiType.CHAR.equals(optype))) { buildFormatString(op, formatString, formatParameters, printfFormat); } else { diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiMethodUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiMethodUtil.java index a92ed0542b2c..7a4d333b15f5 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiMethodUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiMethodUtil.java @@ -15,10 +15,10 @@ */ package com.intellij.psi.util; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.psi.*; import com.intellij.codeInsight.runner.JavaMainMethodProvider; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.util.Condition; +import com.intellij.psi.*; import org.jetbrains.annotations.Nullable; /** @@ -59,7 +59,7 @@ public class PsiMethodUtil { public static boolean isMainMethod(final PsiMethod method) { if (method == null || method.getContainingClass() == null) return false; - if (PsiType.VOID != method.getReturnType()) return false; + if (!PsiType.VOID.equals(method.getReturnType())) return false; if (!method.hasModifierProperty(PsiModifier.STATIC)) return false; if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return false; final PsiParameter[] parameters = method.getParameterList().getParameters(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java index e6781ce9ed50..4c70eeffdf63 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -658,7 +658,16 @@ public class PsiImplUtil { findApplicableTarget((PsiAnnotation)element, TargetType.TYPE_USE) == TargetType.TYPE_USE; } - @Nullable + public static void collectTypeUseAnnotations(@NotNull PsiModifierList modifierList, @NotNull List annotations) { + for (PsiAnnotation annotation : modifierList.getAnnotations()) { + if (isTypeAnnotation(annotation)) { + annotations.add(annotation); + } + } + } + + /** @deprecated use {@link #collectTypeUseAnnotations(PsiModifierList, List)} (to be removed in IDEA 16) */ + @SuppressWarnings("unused") public static List getTypeUseAnnotations(@NotNull PsiModifierList modifierList) { SmartList result = null; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java index 7b8c2632dd70..29305d4d75e6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java @@ -592,10 +592,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme if (!isQualified()) { PsiModifierList modifierList = PsiImplUtil.findNeighbourModifierList(this); if (modifierList != null) { - List typeAnnotations = PsiImplUtil.getTypeUseAnnotations(modifierList); - if (typeAnnotations != null && !typeAnnotations.isEmpty()) { - annotations.addAll(typeAnnotations); - } + PsiImplUtil.collectTypeUseAnnotations(modifierList, annotations); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java index fae8063dbe7e..8df615aa7c91 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java @@ -37,6 +37,8 @@ import org.jetbrains.annotations.Nullable; import java.util.List; public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeElement { + private static final Class[] INTERMEDIATES = {PsiComment.class, PsiWhiteSpace.class, PsiAnnotation.class, PsiTypeParameterList.class}; + @SuppressWarnings({"UnusedDeclaration"}) public PsiTypeElementImpl() { this(JavaElementType.TYPE); @@ -69,7 +71,7 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl } private PsiType calculateType() { - final PsiType inferredType = PsiAugmentProvider.getInferredType(this); + PsiType inferredType = PsiAugmentProvider.getInferredType(this); if (inferredType != null) { return inferredType; } @@ -153,16 +155,13 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl return type == null ? PsiType.NULL : type; } - private void addTypeUseAnnotations(List list) { + private void addTypeUseAnnotations(List annotations) { PsiElement parent = this; while (parent instanceof PsiTypeElement) { - PsiElement left = PsiTreeUtil.skipSiblingsBackward(parent, PsiComment.class, PsiWhiteSpace.class, PsiAnnotation.class); + PsiElement left = PsiTreeUtil.skipSiblingsBackward(parent, INTERMEDIATES); if (left instanceof PsiModifierList) { - List annotations = PsiImplUtil.getTypeUseAnnotations((PsiModifierList)left); - if (annotations != null && !annotations.isEmpty()) { - list.addAll(annotations); - } + PsiImplUtil.collectTypeUseAnnotations((PsiModifierList)left, annotations); break; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ReplaceExpressionUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ReplaceExpressionUtil.java index 6b499e1bfdd5..f131c759a008 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ReplaceExpressionUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ReplaceExpressionUtil.java @@ -75,7 +75,7 @@ public class ReplaceExpressionUtil { } else if (i == JavaElementType.ARRAY_ACCESS_EXPRESSION) { int role = ((CompositeElement)oldParent).getChildRole(oldExpr); - return role != ChildRole.ARRAY_DIMENSION && priority < parentPriority; + return role != ChildRole.ARRAY_DIMENSION && role != ChildRole.INDEX && priority < parentPriority; } else if (i == JavaElementType.ARRAY_INITIALIZER_EXPRESSION) { return false; diff --git a/java/java-tests/testData/codeInsight/completion/smartType/MethodThrows-out.java b/java/java-tests/testData/codeInsight/completion/smartType/MethodThrows-out.java new file mode 100644 index 000000000000..752a63dcd6d2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/MethodThrows-out.java @@ -0,0 +1,10 @@ +class FirstException extends Exception {} +class SecondException extends Exception {} + +interface I { + void method() throws FirstException, SecondException; +} + +class C implements I { + void method() throws FirstException, SecondException; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/MethodThrows.java b/java/java-tests/testData/codeInsight/completion/smartType/MethodThrows.java new file mode 100644 index 000000000000..d5332958a36e --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/MethodThrows.java @@ -0,0 +1,10 @@ +class FirstException extends Exception {} +class SecondException extends Exception {} + +interface I { + void method() throws FirstException, SecondException; +} + +class C implements I { + void method() throws FirstException, Sec; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA147511.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA147511.java new file mode 100644 index 000000000000..a5f20258335b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA147511.java @@ -0,0 +1,47 @@ + +import java.util.Comparator; +import java.util.Optional; +import java.util.function.BinaryOperator; +import java.util.function.Consumer; +import java.util.stream.Stream; + +class Bug { + + public static void main(String[] args) { + Stream tokenStream = Stream.of("hello", "world"); + + Comparator order = Comparator.naturalOrder(); + Min min = tokenStream.collect( + () -> new Min<>(order), + Min::accept, + Min::combine); + + System.out.printf("Min = %s%n", + min.asOptional().orElse(null)); + } + + static class Min implements Consumer { + + private final BinaryOperator minOf; + private T min; + + public Min(Comparator order) { + this.minOf = BinaryOperator.minBy(order); + } + + @Override + public void accept(T t) { + this.min = min != null ? minOf.apply(min, t) : t; + } + + public void combine(Min other) { + if (other.min != null) { + accept(other.min); + } + } + + public Optional asOptional() { + return Optional.ofNullable(min); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addVariableInitializer/after1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addVariableInitializer/after1.java index 7f1e302f38d5..05d7f46088e6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addVariableInitializer/after1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addVariableInitializer/after1.java @@ -3,7 +3,7 @@ class AClass { int f() { - int i = 0; + int i = 0; return i; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addVariableInitializer/after2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addVariableInitializer/after2.java index 23a08dd405e6..01952f29feed 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addVariableInitializer/after2.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addVariableInitializer/after2.java @@ -2,6 +2,6 @@ class AClass { - final AClass f = null; + final AClass f = null; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterMultipleInvoke.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterMultipleInvoke.java index 899b5e69f33f..6b4cbc49001e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterMultipleInvoke.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterMultipleInvoke.java @@ -3,10 +3,10 @@ class A { private final int var; private Main() { - var = 0; + var = 0; } private Main(int var) { this.var = 0; } -} \ No newline at end of file +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterParamWithSameName.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterParamWithSameName.java index b4672ad65e0e..8dda8ee78eb3 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterParamWithSameName.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterParamWithSameName.java @@ -3,6 +3,6 @@ class A { private final int var; private Main(int var) { - this.var = 0; + this.var = 0; } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterSimpleInvoke.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterSimpleInvoke.java index b594c4345357..2155e450fbb2 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterSimpleInvoke.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/initializeFinalFieldInConstructor/afterSimpleInvoke.java @@ -3,6 +3,6 @@ class A { private final int var; private Main() { - var = 0; + var = 0; } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/nullableProblems/NotNullByDefaultFieldNotInitialized.java b/java/java-tests/testData/inspection/nullableProblems/NotNullByDefaultFieldNotInitialized.java new file mode 100644 index 000000000000..07427362783f --- /dev/null +++ b/java/java-tests/testData/inspection/nullableProblems/NotNullByDefaultFieldNotInitialized.java @@ -0,0 +1,15 @@ +import javax.annotation.*; + +@NonnullByDefault +class Test { + Object member; + + private void accessMember() { + member = new Object(); + } +} + + +@Nonnull +@javax.annotation.meta.TypeQualifierDefault(java.lang.annotation.ElementType.FIELD) +@interface NonnullByDefault {} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignature/JavadocOfDeleted.java b/java/java-tests/testData/refactoring/changeSignature/JavadocOfDeleted.java new file mode 100644 index 000000000000..123c9b00992b --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/JavadocOfDeleted.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +class C { + /** + * This is the role - + * @param role another desc + * @param labelExpression blah-blah + * @return return description + */ + public Integer example(int role, String labelExpression) { + switch (role) { + case Constants.FOO: + break; + } + return 1; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/changeSignature/JavadocOfDeleted_after.java b/java/java-tests/testData/refactoring/changeSignature/JavadocOfDeleted_after.java new file mode 100644 index 000000000000..af54692fc2d8 --- /dev/null +++ b/java/java-tests/testData/refactoring/changeSignature/JavadocOfDeleted_after.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +class C { + /** + * This is the role - + * @param role another desc + * @return return description + */ + public Integer example(int role) { + switch (role) { + case Constants.FOO: + break; + } + return 1; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineLocal/ArrayAccessPriority.java b/java/java-tests/testData/refactoring/inlineLocal/ArrayAccessPriority.java new file mode 100644 index 000000000000..adea1fa10edc --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/ArrayAccessPriority.java @@ -0,0 +1,6 @@ +class C { + void f(int[] a, int i) { + int i1 = i + 1; + int temp = a[i1]; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineLocal/ArrayAccessPriority.java.after b/java/java-tests/testData/refactoring/inlineLocal/ArrayAccessPriority.java.after new file mode 100644 index 000000000000..bf9e8dc573ea --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/ArrayAccessPriority.java.after @@ -0,0 +1,5 @@ +class C { + void f(int[] a, int i) { + int temp = a[i + 1]; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/after/A.java b/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/after/A.java new file mode 100644 index 000000000000..8a58812a49b2 --- /dev/null +++ b/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/after/A.java @@ -0,0 +1,2 @@ +public interface A { +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/after/B.java b/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/after/B.java new file mode 100644 index 000000000000..cc08541ae1bc --- /dev/null +++ b/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/after/B.java @@ -0,0 +1,13 @@ +public class B { + + public static final String FOO = "FOO"; +} + +class U { + public void example(String foo) { + switch (foo) { + case B.FOO: + break; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/before/A.java b/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/before/A.java new file mode 100644 index 000000000000..0451878b749f --- /dev/null +++ b/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/before/A.java @@ -0,0 +1,3 @@ +public interface A { + public static final String FOO = "FOO"; +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/before/B.java b/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/before/B.java new file mode 100644 index 000000000000..309cd8c107c3 --- /dev/null +++ b/java/java-tests/testData/refactoring/moveMembers/stringConstantInSwitchLabelExpression/before/B.java @@ -0,0 +1,12 @@ +public class B { + +} + +class U { + public void example(String foo) { + switch (foo) { + case A.FOO: + break; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index e45a9866d2c9..a48109935ecf 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -428,6 +428,8 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { public void testJavadocThrows() throws Throwable { doTest(); } + public void testMethodThrows() throws Throwable { doTest(); } + public void testDoNotExcludeAssignedVariable() throws Throwable { doTest(); } public void testArrayIndexTailType() throws Throwable { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/InferredTypeTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/InferredTypeTest.java index b6a1729c4845..d17ee3c2731e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/InferredTypeTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/InferredTypeTest.java @@ -80,6 +80,7 @@ public class InferredTypeTest extends LightCodeInsightFixtureTestCase { final PsiJavaFile file = (PsiJavaFile)myFixture.addFileToProject("R.java", "public interface R {@D void run();}"); final PsiClass psiClass = file.getClasses()[0]; final PsiMethod method = psiClass.getMethods()[0]; + //noinspection UsePrimitiveTypes assertFalse(PsiType.VOID == method.getReturnType()); myFixture.configureByText("a.java", "class A {{R r = () -> {};}} "); myFixture.checkHighlighting(false, false, false); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java index b24d597f2c28..26d02b495ac3 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java @@ -446,6 +446,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testIDEA147511() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/psi/AnnotatedTypeTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/psi/AnnotatedTypeTest.groovy index 98d166167804..bb2e2ba20a0b 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/psi/AnnotatedTypeTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/psi/AnnotatedTypeTest.groovy @@ -40,8 +40,8 @@ class AnnotatedTypeTest extends LightCodeInsightFixtureTestCase { class I { } } - class E1 extends Exception { } - class E2 extends Exception { }""".stripIndent()) + @SuppressWarnings("ExceptionClassNameDoesntEndWithException") class E1 extends Exception { } + @SuppressWarnings("ExceptionClassNameDoesntEndWithException") class E2 extends Exception { }""".stripIndent()) } public void testPrimitiveArrayType() { @@ -78,20 +78,32 @@ class AnnotatedTypeTest extends LightCodeInsightFixtureTestCase { public void testDisjunctionType() { def psi = factory.createStatementFromText("try { } catch (@A @TA(1) E1 | @TA(2) E2 e) { }", context) as PsiTryStatement - assertTypeText(psi.catchBlockParameters[0].type, "pkg.@pkg.TA(1) E1 | pkg.@pkg.TA(2) E2", "pkg.E1 | pkg.E2") + assertTypeText psi.catchBlockParameters[0].type, "pkg.@pkg.TA(1) E1 | pkg.@pkg.TA(2) E2", "pkg.E1 | pkg.E2" } public void testDiamondType() { def psi = factory.createStatementFromText("Class<@TA String> cs = new Class<>()", context) as PsiDeclarationStatement def var = psi.declaredElements[0] as PsiVariable - assertTypeText(var.initializer.type, "java.lang.Class", "java.lang.Class") + assertTypeText var.initializer.type, "java.lang.Class", "java.lang.Class" } public void testImmediateClassType() { def aClass = myFixture.javaFacade.findClass(CommonClassNames.JAVA_LANG_OBJECT) def annotations = factory.createParameterFromText("@TA int x", context).modifierList.annotations def type = new PsiImmediateClassType(aClass, PsiSubstitutor.EMPTY, LanguageLevel.JDK_1_8, annotations) - assertTypeText(type, "java.lang.@pkg.TA Object", CommonClassNames.JAVA_LANG_OBJECT) + assertTypeText type, "java.lang.@pkg.TA Object", CommonClassNames.JAVA_LANG_OBJECT + } + + public void testFieldType() { + def psi = factory.createFieldFromText("@A @TA(1) String f;", context) + assertTypeText psi.type, "java.lang.@pkg.TA(1) String", "java.lang.String" + assertAnnotations psi.type, "@TA(1)" + } + + public void testMethodReturnType() { + def psi = factory.createMethodFromText("@A @TA(1) String m() { return null; }", context) + assertTypeText psi.returnType, "java.lang.@pkg.TA(1) String", "java.lang.String" + assertAnnotations psi.returnType, "@TA(1)" } private void doTest(String text, String annotated, String canonical) { @@ -102,4 +114,8 @@ class AnnotatedTypeTest extends LightCodeInsightFixtureTestCase { assert type.getCanonicalText(true) == annotated assert type.getCanonicalText(false) == canonical } + + private static void assertAnnotations(PsiType type, String... annotations) { + assert type.annotations.collect { it.text } == annotations.toList() + } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java index e0c38a3913f4..4a27815e27d2 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java @@ -59,6 +59,11 @@ public class NullableStuffInspectionTest extends LightCodeInsightFixtureTestCase doTest(); } + public void testNotNullByDefaultFieldNotInitialized() { + DataFlowInspectionTest.addJavaxNullabilityAnnotations(myFixture); + doTest(); + } + public void testNotNullAnnotationChecksInChildClassMethods() { doTest(); } public void testGetterSetterProblems() throws Exception{ doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/psi/PsiConcurrencyStressTest.java b/java/java-tests/testSrc/com/intellij/psi/PsiConcurrencyStressTest.java index 32fed469fecd..5e2f89a10f3c 100644 --- a/java/java-tests/testSrc/com/intellij/psi/PsiConcurrencyStressTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/PsiConcurrencyStressTest.java @@ -38,8 +38,11 @@ import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.SkipSlowTestLocally; import com.intellij.testFramework.Timings; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import java.util.Collections; +import java.util.List; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -75,7 +78,7 @@ public class PsiConcurrencyStressTest extends DaemonAnalyzerTestCase { final CountDownLatch reads = new CountDownLatch(numOfThreads); final Random random = new Random(); - for (int i = 0; i < numOfThreads; i++) { + List threads = ContainerUtil.map(Collections.nCopies(numOfThreads, ""), i -> new Thread(() -> { for (int i1 = 0; i1 < readIterations; i1++) { if (myPsiManager == null) return; @@ -86,8 +89,8 @@ public class PsiConcurrencyStressTest extends DaemonAnalyzerTestCase { } reads.countDown(); - }, "stress thread" + i).start(); - } + }, "stress thread" + i)); + threads.forEach(Thread::start); final Document document = documentManager.getDocument(myFile); @@ -107,6 +110,15 @@ public class PsiConcurrencyStressTest extends DaemonAnalyzerTestCase { } assertTrue("Timed out", reads.await(5, TimeUnit.MINUTES)); + ContainerUtil.process(threads, thread -> { + try { + thread.join(); + return true; + } + catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); } private static void mark(final String s) { diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/FileIndentOptionsProviderTest.kt b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/FileIndentOptionsProviderTest.kt new file mode 100644 index 000000000000..973f3c494c35 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/FileIndentOptionsProviderTest.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.codeStyle.autodetect + +import com.intellij.openapi.editor.EditorFactory +import com.intellij.openapi.editor.impl.EditorImpl +import com.intellij.openapi.extensions.ExtensionPoint +import com.intellij.openapi.extensions.Extensions +import com.intellij.openapi.extensions.LoadingOrder +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.codeStyle.FileIndentOptionsProvider +import com.intellij.testFramework.LightPlatformTestCase +import org.junit.Test +import org.mockito.Matchers +import org.mockito.Mockito.* + +class ViewerEditorTest: LightPlatformTestCase() { + lateinit var mockProvider: FileIndentOptionsProvider + lateinit var extensionPoint: ExtensionPoint + + override fun setUp() { + super.setUp() + extensionPoint = Extensions.getRootArea().getExtensionPoint(FileIndentOptionsProvider.EP_NAME) + mockProvider = mock(FileIndentOptionsProvider::class.java) + extensionPoint.registerExtension(mockProvider, LoadingOrder.FIRST) + } + + override fun tearDown() { + extensionPoint.unregisterExtension(mockProvider) + super.tearDown() + } + + @Test + fun `test do not use file indent option providers for viewer editors`() { + val file = createFile("Test.java", "class Test {}") + val document = PsiDocumentManager.getInstance(getProject()).getDocument(file) + val editor = EditorFactory.getInstance().createEditor(document!!, getProject(), file.virtualFile, true); + try { + (editor as EditorImpl).reinitSettings() + editor.settings.isLineNumbersShown = true + editor.settings.getTabSize(getProject()) + } + finally { + EditorFactory.getInstance().releaseEditor(editor) + } + verify(mockProvider, never()).getIndentOptions(Matchers.any(), Matchers.any()) + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java index eabe458396a2..00adb05989c3 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java @@ -62,7 +62,7 @@ public class JavaAutoDetectIndentPerformanceTest extends AbstractIndentAutoDetec AbstractIndentAutoDetectionTest.detectIndentOptions(); PlatformTestUtil - .startPerformanceTest("Detecting indent on hot file", 30, AbstractIndentAutoDetectionTest::detectIndentOptions) + .startPerformanceTest("Detecting indent on hot file", 40, AbstractIndentAutoDetectionTest::detectIndentOptions) .cpuBound() .assertTiming(); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java index 3652f87a7880..afcb86dc945a 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTest.java @@ -247,6 +247,12 @@ public class ChangeSignatureTest extends ChangeSignatureBaseTest { }, false); } + public void testJavadocOfDeleted() { + doTest(null, new ParameterInfoImpl[]{ + new ParameterInfoImpl(0, "role", PsiType.INT), + }, false); + } + public void testCovariantReturnType() { doTest(CommonClassNames.JAVA_LANG_RUNNABLE, new ParameterInfoImpl[0], false); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/MoveMembersTest.java b/java/java-tests/testSrc/com/intellij/refactoring/MoveMembersTest.java index e1e66c483fc4..79435401350a 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/MoveMembersTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/MoveMembersTest.java @@ -18,7 +18,6 @@ package com.intellij.refactoring; import com.intellij.JavaTestUtil; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.roots.LanguageLevelProjectExtension; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; @@ -174,7 +173,11 @@ public class MoveMembersTest extends MultiFileTestCase { public void testEscalateVisibility1() throws Exception { doTest("A", "B", true, VisibilityUtil.ESCALATE_VISIBILITY, 0); } - + + public void testStringConstantInSwitchLabelExpression() throws Exception { + doTest("A", "B", true, VisibilityUtil.ESCALATE_VISIBILITY, 0); + } + public void testMultipleWithDependencies() throws Exception { doTest("A", "B", true, VisibilityUtil.ESCALATE_VISIBILITY, 0, 1); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java index 6650bb7b6bed..11c62b549b68 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java @@ -244,6 +244,10 @@ public class InlineLocalTest extends LightCodeInsightTestCase { doTest(true); } + public void testArrayAccessPriority() throws Exception { + doTest(true); + } + public void testLocalVarInsideLambdaBodyWriteUsage() throws Exception { doTest(true, "Cannot perform refactoring.\n" + "Variable 'hello' is accessed for writing"); diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java index b2b44aebd867..2e63ea33adec 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java @@ -32,6 +32,7 @@ import com.intellij.structuralsearch.plugin.replace.impl.Replacer; import com.intellij.structuralsearch.plugin.ui.Configuration; import com.intellij.structuralsearch.plugin.ui.SearchContext; import com.intellij.structuralsearch.plugin.ui.UIUtil; +import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -382,7 +383,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { private void checkModifier(final String name) { if (!MatchOptions.INSTANCE_MODIFIER_NAME.equals(name) && !PsiModifier.PACKAGE_LOCAL.equals(name) && - Arrays.binarySearch(JavaMatchingVisitor.MODIFIERS, name) < 0 + ArrayUtil.find(JavaMatchingVisitor.MODIFIERS, name) < 0 ) { throw new MalformedPatternException(SSRBundle.message("invalid.modifier.type",name)); } @@ -530,7 +531,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { handleMethodParameter(buf, info, matchMap); replacementString = buf.toString(); } - else if (match.getAllSons().size() > 0 && !match.isScopeMatch()) { + else if (match.hasSons() && !match.isScopeMatch()) { // compound matches StringBuilder buf = new StringBuilder(); MatchResult r = null; @@ -550,7 +551,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { } } else if (info.isStatementContext()) { - final PsiElement previousElement = previous.getMatchRef().getElement(); + final PsiElement previousElement = previous.getMatch(); if (!(previousElement instanceof PsiComment) && ( buf.charAt(buf.length() - 1) != '}' || @@ -720,15 +721,15 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { } } - private static void appendParameter(final StringBuilder buf, final MatchResult _matchResult) { - for(Iterator j = _matchResult.getAllSons().iterator();j.hasNext();) { - buf.append(j.next().getMatchImage()).append(' ').append(j.next().getMatchImage()); - } + private static void appendParameter(final StringBuilder buf, final MatchResult matchResult) { + final List sons = matchResult.getAllSons(); + assert sons.size() == 1; + buf.append(sons.get(0).getMatchImage()).append(' ').append(matchResult.getMatchImage()); } private static void removeExtraSemicolonForSingleVarInstanceInMultipleMatch(final ParameterInfo info, MatchResult r, StringBuilder buf) { if (info.isStatementContext()) { - final PsiElement element = r.getMatchRef().getElement(); + final PsiElement element = r.getMatch(); // remove extra ; if (buf.charAt(buf.length()-1)==';' && diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java index 26f77d163a51..d545e0f25f7a 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java @@ -941,13 +941,12 @@ public class JavaMatchingVisitor extends JavaElementVisitor { myMatchingVisitor.getMatchContext().pushResult(); final PsiIdentifier nameIdentifier = var.getNameIdentifier(); - boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(nameIdentifier); + final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(nameIdentifier); final PsiVariable var2 = (PsiVariable)myMatchingVisitor.getElement(); try { myMatchingVisitor.setResult((myMatchingVisitor.matchText(var.getNameIdentifier(), var2.getNameIdentifier()) || isTypedVar) && - ((var.getParent() instanceof PsiClass && ((PsiClass)var.getParent()).isInterface()) || - myMatchingVisitor.match(var.getModifierList(), var2.getModifierList()))); + myMatchingVisitor.match(var.getModifierList(), var2.getModifierList())); if (myMatchingVisitor.getResult()) { final PsiTypeElement typeElement1 = var.getTypeElement(); if (typeElement1 != null) { @@ -972,10 +971,6 @@ public class JavaMatchingVisitor extends JavaElementVisitor { ((PsiCatchSection)var2.getParent()).getCatchBlock() )); } - - if (myMatchingVisitor.getResult() && isTypedVar) { - myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(nameIdentifier, var2.getNameIdentifier())); - } } finally { saveOrDropResult(nameIdentifier, isTypedVar, var2.getNameIdentifier()); @@ -1692,9 +1687,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { myMatchingVisitor.matchSonsOptionally(method.getBody(), method2.getBody())); } finally { - final PsiIdentifier methodNameNode2 = method2.getNameIdentifier(); - - saveOrDropResult(methodNameNode, isTypedVar, methodNameNode2); + saveOrDropResult(methodNameNode, isTypedVar, method2.getNameIdentifier()); } } } diff --git a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java index 011436ce06e2..ff9db05fd70a 100644 --- a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java +++ b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java @@ -16,7 +16,6 @@ package com.intellij.compiler; import com.intellij.compiler.server.BuildManager; -import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.WriteAction; @@ -34,6 +33,7 @@ import com.intellij.testFramework.EdtTestUtil; import com.intellij.util.SmartList; import com.intellij.util.ThrowableRunnable; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; import java.util.List; @@ -44,6 +44,7 @@ public class CompilerTestUtil { private CompilerTestUtil() { } + @TestOnly public static void setupJavacForTests(Project project) { CompilerConfigurationImpl compilerConfiguration = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(project); compilerConfiguration.setDefaultCompiler(compilerConfiguration.getJavacCompiler()); @@ -55,6 +56,7 @@ public class CompilerTestUtil { public static void scanSourceRootsToRecompile(Project project) { } + @TestOnly public static void saveApplicationSettings() { EdtTestUtil.runInEdtAndWait(new Runnable() { @Override @@ -65,6 +67,7 @@ public class CompilerTestUtil { }); } + @TestOnly public static void saveApplicationComponent(final Object appComponent) { EdtTestUtil.runInEdtAndWait(new Runnable() { @Override @@ -79,6 +82,7 @@ public class CompilerTestUtil { ServiceKt.getStateStore(ApplicationManager.getApplication()).saveApplicationComponent(appComponent); } + @TestOnly public static void enableExternalCompiler() { final JavaAwareProjectJdkTableImpl table = JavaAwareProjectJdkTableImpl.getInstanceEx(); new WriteAction() { @@ -89,30 +93,30 @@ public class CompilerTestUtil { }.execute(); } + @TestOnly public static void disableExternalCompiler(@NotNull final Project project) { EdtTestUtil.runInEdtAndWait(new ThrowableRunnable() { @Override public void run() throws Throwable { - JavaAwareProjectJdkTableImpl table = JavaAwareProjectJdkTableImpl.getInstanceEx(); - AccessToken token = WriteAction.start(); - try { - Sdk internalJdk = table.getInternalJdk(); - List modulesToRestore = new SmartList(); - for (Module module : ModuleManager.getInstance(project).getModules()) { - Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); - if (sdk != null && sdk.equals(internalJdk)) { - modulesToRestore.add(module); + final JavaAwareProjectJdkTableImpl table = JavaAwareProjectJdkTableImpl.getInstanceEx(); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + Sdk internalJdk = table.getInternalJdk(); + List modulesToRestore = new SmartList(); + for (Module module : ModuleManager.getInstance(project).getModules()) { + Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); + if (sdk != null && sdk.equals(internalJdk)) { + modulesToRestore.add(module); + } } + table.removeJdk(internalJdk); + for (Module module : modulesToRestore) { + ModuleRootModificationUtil.setModuleSdk(module, internalJdk); + } + BuildManager.getInstance().clearState(project); } - table.removeJdk(internalJdk); - for (Module module : modulesToRestore) { - ModuleRootModificationUtil.setModuleSdk(module, internalJdk); - } - BuildManager.getInstance().clearState(project); - } - finally { - token.finish(); - } + }); } }); } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java index a0ca95579138..05c4afc2548f 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java @@ -61,7 +61,7 @@ public class ConvertFieldToThreadLocalIntention extends PsiElementBaseIntentionA if (psiField.getTypeElement() == null) return false; final PsiType fieldType = psiField.getType(); final PsiClass fieldTypeClass = PsiUtil.resolveClassInType(fieldType); - if (fieldType instanceof PsiPrimitiveType && fieldType != PsiType.VOID || fieldType instanceof PsiArrayType) return true; + if (fieldType instanceof PsiPrimitiveType && !PsiType.VOID.equals(fieldType) || fieldType instanceof PsiArrayType) return true; return fieldTypeClass != null && !Comparing.strEqual(fieldTypeClass.getQualifiedName(), ThreadLocal.class.getName()) && AllowedApiFilterExtension.isClassAllowed(ThreadLocal.class.getName(), element); } @@ -121,7 +121,7 @@ public class ConvertFieldToThreadLocalIntention extends PsiElementBaseIntentionA if (initializer == null) { final PsiType type = psiField.getType(); String initializerText = null; - if (type == PsiType.BOOLEAN) { + if (PsiType.BOOLEAN.equals(type)) { initializerText = "false"; } else if (type instanceof PsiPrimitiveType) { diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java index a4ec46e44838..a6275b650266 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java @@ -39,19 +39,19 @@ public class AtomicConversionRule extends TypeConversionRule { } private static boolean isAtomicTypeMigration(PsiType from, PsiClassType to, PsiExpression context) { - if (from == PsiType.INT && to.getCanonicalText().equals(AtomicInteger.class.getName())) { + if (PsiType.INT.equals(from) && to.getCanonicalText().equals(AtomicInteger.class.getName())) { return true; } if (from.equals(PsiType.INT.createArrayType()) && to.getCanonicalText().equals(AtomicIntegerArray.class.getName())) { return true; } - if (from == PsiType.LONG && to.getCanonicalText().equals(AtomicLong.class.getName())) { + if (PsiType.LONG.equals(from) && to.getCanonicalText().equals(AtomicLong.class.getName())) { return true; } if (from.equals(PsiType.LONG.createArrayType()) && to.getCanonicalText().equals(AtomicLongArray.class.getName())) { return true; } - if (from == PsiType.BOOLEAN && to.getCanonicalText().equals(AtomicBoolean.class.getName())) { + if (PsiType.BOOLEAN.equals(from) && to.getCanonicalText().equals(AtomicBoolean.class.getName())) { return true; } final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(to); diff --git a/platform/core-api/src/com/intellij/lang/CodeDocumentationAwareCommenter.java b/platform/core-api/src/com/intellij/lang/CodeDocumentationAwareCommenter.java index fe07a4a257ef..b90a9a9e9196 100644 --- a/platform/core-api/src/com/intellij/lang/CodeDocumentationAwareCommenter.java +++ b/platform/core-api/src/com/intellij/lang/CodeDocumentationAwareCommenter.java @@ -39,7 +39,7 @@ public interface CodeDocumentationAwareCommenter extends Commenter { * Returns the type of the block comment in the language, * or null if the language does not support block comments. * It is assumed that block comment prefix is not null when block comment type is not null. - * @return the line block comment type. + * @return the block comment type. */ @Nullable IElementType getBlockCommentTokenType(); @@ -48,7 +48,7 @@ public interface CodeDocumentationAwareCommenter extends Commenter { * Returns the type of the documentation comment token in the language, * or null if the language does not support documentation comments. * It is assumed that documentation comment prefix is not null when documentation comment type is not null. - * @return the line block comment type. + * @return the documentation comment type. */ @Nullable IElementType getDocumentationCommentTokenType(); diff --git a/platform/core-api/src/com/intellij/openapi/application/ApplicationInfo.java b/platform/core-api/src/com/intellij/openapi/application/ApplicationInfo.java index 3b57b78c053c..2b1d076af620 100644 --- a/platform/core-api/src/com/intellij/openapi/application/ApplicationInfo.java +++ b/platform/core-api/src/com/intellij/openapi/application/ApplicationInfo.java @@ -36,6 +36,7 @@ public abstract class ApplicationInfo { public abstract String getThirdPartySoftwareURL(); public abstract String getJetbrainsTvUrl(); public abstract String getEvalLicenseUrl(); + public abstract String getKeyConversionUrl(); public abstract Rectangle getAboutLogoRect(); public abstract boolean hasHelp(); diff --git a/platform/core-api/src/com/intellij/openapi/project/DumbService.java b/platform/core-api/src/com/intellij/openapi/project/DumbService.java index 8062d86390b8..fcd2ec68fa29 100644 --- a/platform/core-api/src/com/intellij/openapi/project/DumbService.java +++ b/platform/core-api/src/com/intellij/openapi/project/DumbService.java @@ -64,7 +64,9 @@ public abstract class DumbService { } /** - * Executes the runnable immediately if not in dumb mode, or on AWT Event Dispatch thread when the dumb mode ends. + * Executes the runnable immediately if not in dumb mode, or on AWT Event Dispatch thread after the dumb mode ends. + * Note that it's not guaranteed that the dumb mode won't start again during this runnable execution, it should manage that situation explicitly + * (e.g. by starting a read action; it's still necessary to check isDumb inside the read action). * @param runnable runnable to run */ public abstract void runWhenSmart(@NotNull Runnable runnable); diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java b/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java index 539a8da7341c..975495669f9a 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java @@ -584,11 +584,18 @@ public class VfsUtilCore { } if (file == null) { - if (base == null) return StandardFileSystems.local().findFileByPath(uri); - if (!base.isDirectory()) base = base.getParent(); - if (base == null) return StandardFileSystems.local().findFileByPath(uri); - file = VirtualFileManager.getInstance().findFileByUrl(base.getUrl() + "/" + uri); - if (file == null) return null; + if (base != null && !base.isDirectory()) { + base = base.getParent(); + } + if (base == null) { + file = StandardFileSystems.local().findFileByPath(uri); + if (file == null) { + file = VirtualFileManager.getInstance().findFileByUrl(uri); + } + } + else { + file = VirtualFileManager.getInstance().findFileByUrl(base.getUrl() + "/" + uri); + } } return file; diff --git a/platform/core-impl/src/com/intellij/core/CoreProjectScopeBuilder.java b/platform/core-impl/src/com/intellij/core/CoreProjectScopeBuilder.java index 3f4c6e647d2c..cef8725406ba 100644 --- a/platform/core-impl/src/com/intellij/core/CoreProjectScopeBuilder.java +++ b/platform/core-impl/src/com/intellij/core/CoreProjectScopeBuilder.java @@ -96,7 +96,10 @@ public class CoreProjectScopeBuilder extends ProjectScopeBuilder { @Override public boolean contains(@NotNull VirtualFile file) { - return myFileIndexFacade.isInContent(file); + return myFileIndexFacade.isInContent(file) && + // skip libraries that can be under our project content (IDEA-147584) + !myFileIndexFacade.isInLibraryClasses(file) && + !myFileIndexFacade.isInLibrarySource(file); } @Override diff --git a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java index 6ea1233625a1..3fe63183d244 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java @@ -110,6 +110,7 @@ public class ApplicationInfoImpl extends ApplicationInfoEx { private String myThirdPartySoftwareUrl; private String myJetbrainsTvUrl; private String myEvalLicenseUrl = "https://www.jetbrains.com/company/useterms.html"; + private String myKeyConversionUrl = "https://www.jetbrains.com/shop/eform/keys-exchange"; private Rectangle myAboutLogoRect; @@ -187,6 +188,8 @@ public class ApplicationInfoImpl extends ApplicationInfoEx { private static final String STEPS_PROVIDER = "provider"; private static final String ELEMENT_EVALUATION = "evaluation"; private static final String ATTRIBUTE_EVAL_LICENSE_URL = "license-url"; + private static final String ELEMENT_LICENSING = "licensing"; + private static final String ATTRIBUTE_KEY_CONVERSION_URL = "key-conversion-url"; private static final String ESSENTIAL_PLUGIN = "essential-plugin"; private static final String DEFAULT_PLUGINS_HOST = "http://plugins.jetbrains.com"; @@ -541,6 +544,11 @@ public class ApplicationInfoImpl extends ApplicationInfoEx { return myEvalLicenseUrl; } + @Override + public String getKeyConversionUrl() { + return myKeyConversionUrl; + } + @Override public Rectangle getAboutLogoRect() { return myAboutLogoRect; @@ -836,7 +844,15 @@ public class ApplicationInfoImpl extends ApplicationInfoEx { if (evaluationElement != null) { final String url = evaluationElement.getAttributeValue(ATTRIBUTE_EVAL_LICENSE_URL); if (url != null && !url.isEmpty()) { - myEvalLicenseUrl = url; + myEvalLicenseUrl = url.trim(); + } + } + + Element licensingElement = parentNode.getChild(ELEMENT_LICENSING); + if (licensingElement != null) { + final String url = licensingElement.getAttributeValue(ATTRIBUTE_KEY_CONVERSION_URL); + if (url != null && !url.isEmpty()) { + myKeyConversionUrl = url.trim(); } } diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/EditorDocumentPriorities.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/EditorDocumentPriorities.java index 157231cbbb36..677da409294c 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/EditorDocumentPriorities.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/EditorDocumentPriorities.java @@ -35,9 +35,9 @@ public class EditorDocumentPriorities { public static final int FOLD_MODEL = 60; public static final int LOGICAL_POSITION_CACHE = 65; public static final int EDITOR_TEXT_LAYOUT_CACHE = 70; - public static final int EDITOR_TEXT_WIDTH_CACHE = 75; public static final int LEXER_EDITOR = 80; public static final int SOFT_WRAP_MODEL = 100; + public static final int EDITOR_TEXT_WIDTH_CACHE = 110; public static final int CARET_MODEL = 120; public static final int SELECTION_MODEL = 140; public static final int EDITOR_DOCUMENT_ADAPTER = 160; diff --git a/platform/core-impl/src/com/intellij/psi/stubs/LightStubBuilder.java b/platform/core-impl/src/com/intellij/psi/stubs/LightStubBuilder.java index 5571f2137243..bf95e89dde34 100644 --- a/platform/core-impl/src/com/intellij/psi/stubs/LightStubBuilder.java +++ b/platform/core-impl/src/com/intellij/psi/stubs/LightStubBuilder.java @@ -22,10 +22,10 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.psi.PsiFile; import com.intellij.psi.StubBuilder; +import com.intellij.psi.impl.source.PsiFileImpl; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IFileElementType; import com.intellij.psi.tree.ILightStubFileElementType; -import com.intellij.psi.tree.IStubFileElementType; import com.intellij.util.containers.Stack; import gnu.trove.TIntStack; import org.jetbrains.annotations.NotNull; @@ -45,10 +45,10 @@ public class LightStubBuilder implements StubBuilder { LOG.error("File is not of LanguageFileType: " + fileType + ", " + file); return null; } - Language language = ((LanguageFileType)fileType).getLanguage(); - final IFileElementType contentType = LanguageParserDefinitions.INSTANCE.forLanguage(language).getFileNodeType(); - if (!(contentType instanceof IStubFileElementType)) { - LOG.error("File is not of IStubFileElementType: " + contentType + ", " + file); + assert file instanceof PsiFileImpl; + final IFileElementType contentType = ((PsiFileImpl)file).getElementTypeForStubBuilder(); + if (contentType == null) { + LOG.error("File is not of IStubFileElementType: " + file); return null; } diff --git a/platform/core-impl/src/com/intellij/util/DocumentUtil.java b/platform/core-impl/src/com/intellij/util/DocumentUtil.java index e175e367b666..e88e13e1a90f 100644 --- a/platform/core-impl/src/com/intellij/util/DocumentUtil.java +++ b/platform/core-impl/src/com/intellij/util/DocumentUtil.java @@ -96,6 +96,14 @@ public final class DocumentUtil { return document.getLineStartOffset(lineNumber); } + public static int getLineEndOffset(int offset, @NotNull Document document) { + if (offset < 0 || offset > document.getTextLength()) { + return offset; + } + int lineNumber = document.getLineNumber(offset); + return document.getLineEndOffset(lineNumber); + } + @NotNull public static TextRange getLineTextRange(@NotNull Document document, int line) { return TextRange.create(document.getLineStartOffset(line), document.getLineEndOffset(line)); diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java index f1ed6303c9ff..e4211e70a44f 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java @@ -10,6 +10,7 @@ import com.intellij.openapi.externalSystem.model.project.LibraryPathType; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.service.project.ExternalLibraryPathTypeMapper; import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider; +import com.intellij.openapi.externalSystem.service.project.IdeUIModifiableModelsProvider; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; @@ -22,7 +23,6 @@ import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.RootPolicy; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -110,8 +110,7 @@ public class LibraryDataService extends AbstractProjectDataService> libraryFiles, @NotNull Library.ModifiableModel model, - @NotNull String libraryName) - { + @NotNull String libraryName) { for (Map.Entry> entry : libraryFiles.entrySet()) { for (File file : entry.getValue()) { VirtualFile virtualFile = ExternalSystemUtil.refreshAndFindFileByIoFile(file); @@ -167,6 +166,11 @@ public class LibraryDataService extends AbstractProjectDataService orphanIdeLibraries = ContainerUtil.newSmartList(); final LibraryTable.ModifiableModel librariesModel = modelsProvider.getModifiableProjectLibrariesModel(); for (Library library : librariesModel.getLibraries()) { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/wizard/AbstractExternalProjectImportBuilder.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/wizard/AbstractExternalProjectImportBuilder.java index cf7be530aaa1..109a4ce6070f 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/wizard/AbstractExternalProjectImportBuilder.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/wizard/AbstractExternalProjectImportBuilder.java @@ -33,6 +33,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; import com.intellij.openapi.roots.ui.configuration.ModulesProvider; +import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -124,7 +125,7 @@ public abstract class AbstractExternalProjectImportBuilder modules = ContainerUtil.newSmartList(); final IdeModifiableModelsProvider modelsProvider = isFromUI ? new IdeUIModifiableModelsProvider( @@ -163,46 +164,62 @@ public abstract class AbstractExternalProjectImportBuilder externalProjectNode, + boolean isFromUI, + final List modules, + IdeModifiableModelsProvider modelsProvider, final ExternalProjectSettings projectSettings) { + myProjectDataManager.importData(externalProjectNode, project, modelsProvider, true); + myExternalProjectNode = null; + + // resolve dependencies + final Runnable resolveDependenciesTask = new Runnable() { + @Override + public void run() { + ExternalSystemUtil.refreshProject( + project, myExternalSystemId, projectSettings.getExternalProjectPath(), false, + ProgressExecutionMode.IN_BACKGROUND_ASYNC); + } + }; + if (!isFromUI) { + resolveDependenciesTask.run(); + } + else { + // execute when current dialog is closed + ExternalSystemUtil.invokeLater(project, ModalityState.NON_MODAL, new Runnable() { + @Override + public void run() { + final Module[] committedModules = ModuleManager.getInstance(project).getModules(); + if (ContainerUtil.list(committedModules).containsAll(modules)) { + resolveDependenciesTask.run(); + } + else { + ExternalSystemApiUtil.getLocalSettings(project, myExternalSystemId).forgetExternalProjects( + Collections.singleton(projectSettings.getExternalProjectPath())); + ExternalSystemApiUtil.getSettings(project, myExternalSystemId).unlinkExternalProject( + projectSettings.getExternalProjectPath()); + + ExternalProjectsManager.getInstance(project).forgetExternalProjectData( + myExternalSystemId, projectSettings.getExternalProjectPath()); + } + } + }); + } + } + @NotNull private ExternalProjectSettings getCurrentExternalProjectSettings() { ExternalProjectSettings result = myControl.getProjectSettings().clone(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java index ea449e8ba1be..cff59c10fddf 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java @@ -32,10 +32,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.StandardPatterns; @@ -93,7 +90,7 @@ public class CompletionLookupArranger extends LookupArranger { myLocation = new CompletionLocation(parameters); } - private MultiMap groupItemsBySorter(List source) { + private MultiMap groupItemsBySorter(Iterable source) { MultiMap inputBySorter = MultiMap.createLinked(); for (LookupElement element : source) { inputBySorter.putValue(obtainSorter(element), element); @@ -106,28 +103,30 @@ public class CompletionLookupArranger extends LookupArranger { return myProcess.getSorter(element); } + @NotNull @Override - public Map getRelevanceStrings() { - final LinkedHashMap map = new LinkedHashMap(); - for (LookupElement item : myItems) { - map.put(item, new StringBuilder()); - } - final MultiMap inputBySorter = groupItemsBySorter(new ArrayList(map.keySet())); - - if (inputBySorter.size() > 1) { - for (LookupElement element : map.keySet()) { - map.get(element).append(obtainSorter(element)).append(": "); - } - } - + public Map>> getRelevanceObjects(@NotNull Iterable items, + boolean hideSingleValued) { + final LinkedHashMap>> map = ContainerUtil.newLinkedHashMap(); + final MultiMap inputBySorter = groupItemsBySorter(items); + int sorterNumber = 0; for (CompletionSorterImpl sorter : inputBySorter.keySet()) { - final LinkedHashMap subMap = new LinkedHashMap(); - for (LookupElement element : inputBySorter.get(sorter)) { - subMap.put(element, map.get(element)); + sorterNumber++; + Collection thisSorterItems = inputBySorter.get(sorter); + for (LookupElement element : thisSorterItems) { + map.put(element, ContainerUtil.newArrayList(new Pair("frozen", myFrozenItems.contains(element)), + new Pair("sorter", sorterNumber))); } + ProcessingContext context = createContext(false); Classifier classifier = myClassifiers.get(sorter); - if (classifier != null) { - classifier.describeItems(subMap, createContext(false)); + while (classifier != null) { + List> pairs = classifier.getSortingWeights(thisSorterItems, context); + if (!hideSingleValued || !haveSameWeights(pairs)) { + for (Pair pair : pairs) { + map.get(pair.first).add(Pair.create(classifier.getPresentableName(), pair.second)); + } + } + classifier = classifier.getNext(); } } @@ -135,6 +134,18 @@ public class CompletionLookupArranger extends LookupArranger { } + private static boolean haveSameWeights(List> pairs) { + if (pairs.isEmpty()) return true; + + for (int i = 1; i < pairs.size(); i++) { + if (!Comparing.equal(pairs.get(i).second, pairs.get(0).second)) { + return false; + } + } + + return true; + } + @Override public void addElement(Lookup lookup, LookupElement element, LookupElementPresentation presentation) { StatisticsWeigher.clearBaseStatisticsInfo(element); @@ -570,12 +581,19 @@ public class CompletionLookupArranger extends LookupArranger { private final LookupImpl myLookup; private AlphaClassifier(LookupImpl lookup) { - super(null); + super(null, "alpha"); myLookup = lookup; } + @NotNull @Override - public Iterable classify(Iterable source, ProcessingContext context) { + public List> getSortingWeights(@NotNull Iterable items, @NotNull ProcessingContext context) { + return Collections.emptyList(); + } + + @NotNull + @Override + public Iterable classify(@NotNull Iterable source, @NotNull ProcessingContext context) { return sortByPresentation(source, myLookup); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsComparable.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsComparable.java new file mode 100644 index 000000000000..ba72751ee357 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsComparable.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.psi.statistics.StatisticsInfo; +import org.jetbrains.annotations.NotNull; + +/** + * @author peter + */ +public class StatisticsComparable implements Comparable { + private final int myScalar; + private final StatisticsInfo myStatisticsInfo; + + public StatisticsComparable(int scalar, @NotNull StatisticsInfo statisticsInfo) { + myScalar = scalar; + myStatisticsInfo = statisticsInfo; + } + + public int getScalar() { + return myScalar; + } + + @NotNull + public StatisticsInfo getStatisticsInfo() { + return myStatisticsInfo; + } + + @Override + public String toString() { + return String.valueOf(myScalar); + } + + @Override + public int compareTo(StatisticsComparable o) { + return myScalar < o.myScalar ? -1 : myScalar == o.myScalar ? 0 : 1; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java index 176827ce4070..f6ee7eeb9cb9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java @@ -22,8 +22,10 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Pair; import com.intellij.psi.statistics.StatisticsInfo; import com.intellij.psi.statistics.StatisticsManager; +import com.intellij.util.Function; import com.intellij.util.ProcessingContext; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; @@ -49,19 +51,19 @@ public class StatisticsWeigher extends CompletionWeigher { public static class LookupStatisticsWeigher extends Classifier { private final CompletionLocation myLocation; - private final Map myWeights = new IdentityHashMap(); - @SuppressWarnings("unchecked") private final Set myNoStats = new THashSet(TObjectHashingStrategy.IDENTITY); + private final Map myWeights = ContainerUtil.newIdentityHashMap(); + private final Set myNoStats = ContainerUtil.newIdentityTroveSet(); private int myPrefixChanges; public LookupStatisticsWeigher(CompletionLocation location, Classifier next) { - super(next); + super(next, "stats"); myLocation = location; } @Override - public void addElement(LookupElement element, ProcessingContext context) { + public void addElement(@NotNull LookupElement element, @NotNull ProcessingContext context) { StatisticsInfo baseInfo = getBaseStatisticsInfo(element, myLocation); - myWeights.put(element, weigh(element, baseInfo, context.get(CompletionLookupArranger.WEIGHING_CONTEXT))); + myWeights.put(element, new StatisticsComparable(weigh(element, baseInfo, context.get(CompletionLookupArranger.WEIGHING_CONTEXT)), baseInfo)); if (baseInfo == StatisticsInfo.EMPTY) { myNoStats.add(element); } @@ -76,8 +78,9 @@ public class StatisticsWeigher extends CompletionWeigher { } } + @NotNull @Override - public Iterable classify(Iterable source, final ProcessingContext context) { + public Iterable classify(@NotNull Iterable source, @NotNull final ProcessingContext context) { checkPrefixChanged(context); final Collection> byWeight = buildMapByWeight(source, context).descendingMap().values(); @@ -122,7 +125,7 @@ public class StatisticsWeigher extends CompletionWeigher { private TreeMap> buildMapByWeight(Iterable source, ProcessingContext context) { TreeMap> map = new TreeMap>(); for (LookupElement element : source) { - final int weight = getWeight(element, context.get(CompletionLookupArranger.WEIGHING_CONTEXT)); + final int weight = getWeight(element, context.get(CompletionLookupArranger.WEIGHING_CONTEXT)).getScalar(); List list = map.get(weight); if (list == null) { map.put(weight, list = new SmartList()); @@ -132,10 +135,11 @@ public class StatisticsWeigher extends CompletionWeigher { return map; } - private int getWeight(LookupElement t, WeighingContext context) { - Integer w = myWeights.get(t); + private StatisticsComparable getWeight(LookupElement t, WeighingContext context) { + StatisticsComparable w = myWeights.get(t); if (w == null) { - myWeights.put(t, w = weigh(t, getBaseStatisticsInfo(t, myLocation), context)); + StatisticsInfo info = getBaseStatisticsInfo(t, myLocation); + myWeights.put(t, w = new StatisticsComparable(weigh(t, info, context), info)); } return w; } @@ -151,21 +155,20 @@ public class StatisticsWeigher extends CompletionWeigher { return minRecency == Integer.MAX_VALUE ? useCount : 100 - minRecency; } + @NotNull @Override - public void describeItems(LinkedHashMap map, ProcessingContext context) { + public List> getSortingWeights(@NotNull Iterable items, @NotNull final ProcessingContext context) { checkPrefixChanged(context); - for (LookupElement element : map.keySet()) { - StringBuilder builder = map.get(element); - if (builder.length() > 0) { - builder.append(", "); + return ContainerUtil.map(items, new Function>() { + @Override + public Pair fun(LookupElement lookupElement) { + return new Pair(lookupElement, getWeight(lookupElement, context.get(CompletionLookupArranger.WEIGHING_CONTEXT))); } - builder.append("stats=").append(getWeight(element, context.get(CompletionLookupArranger.WEIGHING_CONTEXT))); - } - super.describeItems(map, context); + }); } @Override - public void removeElement(LookupElement element, ProcessingContext context) { + public void removeElement(@NotNull LookupElement element, @NotNull ProcessingContext context) { myWeights.remove(element); myNoStats.remove(element); super.removeElement(element, context); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java index 9e7a9cb2e9a9..efc4401f2d9b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java @@ -19,6 +19,8 @@ import com.intellij.codeInsight.completion.CompletionUtil; import com.intellij.codeInsight.lookup.Classifier; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; +import com.intellij.util.Function; import com.intellij.util.ProcessingContext; import com.intellij.util.containers.*; import gnu.trove.THashSet; @@ -39,20 +41,18 @@ public class LiftShorterItemsClassifier extends Classifier { private final MultiMap myElements = createMultiMap(false); private final MultiMap myToLift = createMultiMap(true); private final MultiMap myReversedToLift = createMultiMap(true); - private final String myName; private final LiftingCondition myCondition; private final boolean myLiftBefore; private int myCount = 0; public LiftShorterItemsClassifier(String name, Classifier next, LiftingCondition condition, boolean liftBefore) { - super(next); - myName = name; + super(next, name); myCondition = condition; myLiftBefore = liftBefore; } @Override - public void addElement(LookupElement added, ProcessingContext context) { + public void addElement(@NotNull LookupElement added, @NotNull ProcessingContext context) { myCount++; for (String string : CompletionUtil.iterateLookupStrings(added)) { @@ -96,8 +96,9 @@ public class LiftShorterItemsClassifier extends Classifier { } } + @NotNull @Override - public Iterable classify(Iterable source, ProcessingContext context) { + public Iterable classify(@NotNull Iterable source, @NotNull ProcessingContext context) { return liftShorterElements(source, null, context); } @@ -113,25 +114,21 @@ public class LiftShorterItemsClassifier extends Classifier { return new LiftingIterable(srcSet, context, source, lifted); } + @NotNull @Override - public void describeItems(LinkedHashMap map, ProcessingContext context) { + public List> getSortingWeights(@NotNull Iterable items, @NotNull ProcessingContext context) { final THashSet lifted = newIdentityTroveSet(); - liftShorterElements(new ArrayList(map.keySet()), lifted, context); - if (!lifted.isEmpty()) { - for (LookupElement element : map.keySet()) { - final StringBuilder builder = map.get(element); - if (builder.length() > 0) { - builder.append(", "); - } - - builder.append(myName).append("=").append(lifted.contains(element)); + liftShorterElements(ContainerUtil.newArrayList(items), lifted, context); + return ContainerUtil.map(items, new Function>() { + @Override + public Pair fun(LookupElement element) { + return new Pair(element, lifted.contains(element)); } - } - super.describeItems(map, context); + }); } @Override - public void removeElement(LookupElement element, ProcessingContext context) { + public void removeElement(@NotNull LookupElement element, @NotNull ProcessingContext context) { for (String s : CompletionUtil.iterateLookupStrings(element)) { myElements.remove(s, element); if (myElements.get(s).isEmpty()) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java index f6b857334c01..1e3ee7746669 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java @@ -27,6 +27,7 @@ import com.intellij.codeInsight.daemon.ReferenceImporter; import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.intention.impl.FileLevelIntentionComponent; import com.intellij.codeInsight.intention.impl.IntentionHintComponent; +import com.intellij.diagnostic.ThreadDumper; import com.intellij.ide.PowerSaveMode; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.Disposable; @@ -343,7 +344,8 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzerEx implements Pers final DaemonProgressIndicator progress = createUpdateProgress(); myPassExecutorService.submitPasses(map, progress); try { - while (progress.isRunning()) { + long start = System.currentTimeMillis(); + while (progress.isRunning() && System.currentTimeMillis() < start + 5*60*1000) { wrap(new ThrowableRunnable() { @Override public void run() throws Throwable { @@ -358,6 +360,9 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzerEx implements Pers } }); } + if (progress.isRunning()) { + throw new RuntimeException("Highlighting still running after "+(System.currentTimeMillis()-start)/1000+" seconds.\n"+ ThreadDumper.dumpThreadsToString()); + } final HighlightingSessionImpl session = (HighlightingSessionImpl)HighlightingSessionImpl.getOrCreateHighlightingSession(file, textEditors.get(0).getEditor(), progress, null); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/CachingComparingClassifier.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/CachingComparingClassifier.java index dba7c55964f3..5597f1483440 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/CachingComparingClassifier.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/CachingComparingClassifier.java @@ -17,13 +17,15 @@ package com.intellij.codeInsight.lookup; import com.intellij.codeInsight.completion.CompletionLookupArranger; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.psi.ForceableComparable; import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.IdentityHashMap; -import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; /** @@ -52,13 +54,14 @@ public class CachingComparingClassifier extends ComparingClassifier classify(Iterable source, ProcessingContext context) { + public Iterable classify(@NotNull Iterable source, @NotNull ProcessingContext context) { if (!myWeigher.isPrefixDependent() && myPrimitive) { return myNext.classify(source, context); } @@ -75,14 +78,15 @@ public class CachingComparingClassifier extends ComparingClassifier map, ProcessingContext context) { + public List> getSortingWeights(@NotNull Iterable items, @NotNull ProcessingContext context) { checkPrefixChanged(context); - super.describeItems(map, context); + return super.getSortingWeights(items, context); } @Override - public void addElement(LookupElement t, ProcessingContext context) { + public void addElement(@NotNull LookupElement t, @NotNull ProcessingContext context) { Comparable weight = myWeigher.weigh(t, context.get(CompletionLookupArranger.WEIGHING_CONTEXT)); if (weight instanceof ForceableComparable) { ((ForceableComparable)weight).force(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/Classifier.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/Classifier.java index 42ced4a0c60f..5f33e16bf184 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/Classifier.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/Classifier.java @@ -15,37 +15,55 @@ */ package com.intellij.codeInsight.lookup; +import com.intellij.openapi.util.Pair; import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.LinkedHashMap; +import java.util.List; /** * @author peter */ public abstract class Classifier { protected final Classifier myNext; + private final String myName; - protected Classifier(Classifier next) { + protected Classifier(@Nullable Classifier next, String name) { myNext = next; + myName = name; } - public void addElement(T t, ProcessingContext context) { + public void addElement(@NotNull T t, @NotNull ProcessingContext context) { if (myNext != null) { myNext.addElement(t, context); } } - public abstract Iterable classify(Iterable source, ProcessingContext context); + @NotNull + public abstract Iterable classify(@NotNull Iterable source, @NotNull ProcessingContext context); - public void describeItems(LinkedHashMap map, ProcessingContext context) { - if (myNext != null) { - myNext.describeItems(map, context); - } + /** + * @return a mapping from the given items to objects (e.g. Comparable instances) used to sort the items in {@link #classify(Iterable, ProcessingContext)}. + * May return an empty list if there are no suitable objects available. + * Used for diagnostics and statistic collection. + */ + @NotNull + public abstract List> getSortingWeights(@NotNull Iterable items, @NotNull ProcessingContext context); + + @Nullable + public final Classifier getNext() { + return myNext; } - public void removeElement(T element, ProcessingContext context) { + public void removeElement(@NotNull T element, @NotNull ProcessingContext context) { if (myNext != null) { myNext.removeElement(element, context); } } + + @NotNull + public final String getPresentableName() { + return myName; + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java index d399fac02f3a..96faa2fd8c31 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java @@ -15,11 +15,13 @@ */ package com.intellij.codeInsight.lookup; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.Pair; +import com.intellij.util.Function; import com.intellij.util.ProcessingContext; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.FlatteningIterator; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -28,24 +30,19 @@ import java.util.*; * @author peter */ public abstract class ComparingClassifier extends Classifier { - protected final String myName; private final boolean myNegated; - public ComparingClassifier(Classifier next, String name) { - this(next, name, false); - } - protected ComparingClassifier(Classifier next, String name, boolean negated) { - super(next); - myName = name; + super(next, name); myNegated = negated; } @Nullable public abstract Comparable getWeight(T t, ProcessingContext context); + @NotNull @Override - public Iterable classify(final Iterable source, final ProcessingContext context) { + public Iterable classify(@NotNull final Iterable source, @NotNull final ProcessingContext context) { List nulls = null; TreeMap> map = new TreeMap>(); for (T t : source) { @@ -79,21 +76,14 @@ public abstract class ComparingClassifier extends Classifier { }; } + @NotNull @Override - public void describeItems(LinkedHashMap map, ProcessingContext context) { - Map weights = new IdentityHashMap(); - for (T t : map.keySet()) { - weights.put(t, String.valueOf(getWeight(t, context))); - } - if (new HashSet(weights.values()).size() > 1 || ApplicationManager.getApplication().isUnitTestMode()) { - for (T t : map.keySet()) { - final StringBuilder builder = map.get(t); - if (builder.length() > 0) { - builder.append(", "); - } - builder.append(myName).append("=").append(weights.get(t)); + public List> getSortingWeights(@NotNull Iterable items, @NotNull final ProcessingContext context) { + return ContainerUtil.map(items, new Function>() { + @Override + public Pair fun(T t) { + return new Pair(t, getWeight(t, context)); } - } - super.describeItems(map, context); + }); } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupArranger.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupArranger.java index b58ac2ce3a65..aea154223bac 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupArranger.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/LookupArranger.java @@ -122,7 +122,15 @@ public abstract class LookupArranger { return myMatchingItems; } - public Map getRelevanceStrings() { + /** + * @param items the items to give relevance weight for + * @param hideSingleValued whether criteria that gave same values for all items should be skipped + * @return for each item, an (ordered) map of criteria used for lookup relevance sorting + * along with the objects representing the weights in these criteria + */ + @NotNull + public Map>> getRelevanceObjects(@NotNull Iterable items, + boolean hideSingleValued) { return Collections.emptyMap(); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index bc16f354e5eb..ea0f8a4853e5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -67,10 +67,8 @@ import javax.swing.event.ListSelectionListener; import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; -import java.util.Collection; -import java.util.HashMap; +import java.util.*; import java.util.List; -import java.util.Map; public class LookupImpl extends LightweightHint implements LookupEx, Disposable, WeighingContext { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.lookup.impl.LookupImpl"); @@ -1153,9 +1151,10 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable, return true; } - public Map getRelevanceStrings() { + @NotNull + public Map>> getRelevanceObjects(@NotNull Iterable items, boolean hideSingleValued) { synchronized (myList) { - return myPresentableArranger.getRelevanceStrings(); + return myPresentableArranger.getRelevanceObjects(items, hideSingleValued); } } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/DefaultSearchEverywhereClassifier.java b/platform/lang-impl/src/com/intellij/ide/actions/DefaultSearchEverywhereClassifier.java new file mode 100644 index 000000000000..2556599838f6 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/DefaultSearchEverywhereClassifier.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.actions; + +import com.intellij.lang.Language; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; + +public class DefaultSearchEverywhereClassifier implements SearchEverywhereClassifier { + @Override + public boolean isClass(@Nullable Object o) { + return o instanceof PsiElement; + } + + @Override + public boolean isSymbol(@Nullable Object o) { + if (o instanceof PsiElement) { + final PsiElement e = (PsiElement)o; + return !e.getLanguage().is(Language.findLanguageByID("JAVA")) || !(e.getParent() instanceof PsiFile); + } + return false; + } + + @Nullable + @Override + public VirtualFile getVirtualFile(@NotNull Object o) { + if (o instanceof PsiElement) { + final PsiElement element = (PsiElement)o; + final PsiFile file = element.getContainingFile(); + return file != null ? file.getVirtualFile() : null; + } + return null; + } + + @Nullable + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 309c78e113a1..d6118511a107 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -49,6 +49,7 @@ import com.intellij.lang.Language; import com.intellij.lang.LanguagePsiElementExternalizer; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.NavigationItem; +import com.intellij.navigation.PsiElementNavigationItem; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; @@ -1106,23 +1107,29 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA Matcher matcher = NameUtil.buildMatcher(pattern, 0, true, true); if (isMoreItem(index)) { cmp = More.get(isSelected); - } else if (value instanceof VirtualFile - && myProject != null - && ((((VirtualFile)value).isDirectory() && (file = PsiManager.getInstance(myProject).findDirectory((VirtualFile)value)) != null ) - || (file = PsiManager.getInstance(myProject).findFile((VirtualFile)value)) != null)) { - myFileRenderer.setPatternMatcher(matcher); - cmp = myFileRenderer.getListCellRendererComponent(list, file, index, isSelected, cellHasFocus); - } else if (value instanceof PsiElement) { - myFileRenderer.setPatternMatcher(matcher); - cmp = myFileRenderer.getListCellRendererComponent(list, value, index, isSelected, isSelected); - } else if (value instanceof GotoActionModel.ActionWrapper) { - cmp = myActionsRenderer.getListCellRendererComponent(list, new GotoActionModel.MatchedValue(((GotoActionModel.ActionWrapper)value), pattern), index, isSelected, isSelected); } else { - cmp = super.getListCellRendererComponent(list, value, index, isSelected, isSelected); - final JPanel p = new JPanel(new BorderLayout()); - p.setBackground(UIUtil.getListBackground(isSelected)); - p.add(cmp, BorderLayout.CENTER); - cmp = p; + cmp = SearchEverywhereClassifier.EP_Manager.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + } + + if (cmp == null) { + if (value instanceof VirtualFile + && myProject != null + && ((((VirtualFile)value).isDirectory() && (file = PsiManager.getInstance(myProject).findDirectory((VirtualFile)value)) != null) + || (file = PsiManager.getInstance(myProject).findFile((VirtualFile)value)) != null)) { + myFileRenderer.setPatternMatcher(matcher); + cmp = myFileRenderer.getListCellRendererComponent(list, file, index, isSelected, cellHasFocus); + } else if (value instanceof PsiElement) { + myFileRenderer.setPatternMatcher(matcher); + cmp = myFileRenderer.getListCellRendererComponent(list, value, index, isSelected, isSelected); + } else if (value instanceof GotoActionModel.ActionWrapper) { + cmp = myActionsRenderer.getListCellRendererComponent(list, new GotoActionModel.MatchedValue(((GotoActionModel.ActionWrapper)value), pattern), index, isSelected, isSelected); + } else { + cmp = super.getListCellRendererComponent(list, value, index, isSelected, isSelected); + final JPanel p = new JPanel(new BorderLayout()); + p.setBackground(UIUtil.getListBackground(isSelected)); + p.add(cmp, BorderLayout.CENTER); + cmp = p; + } } if (myLocationString != null || value instanceof BooleanOptionDescription) { final JPanel panel = new JPanel(new BorderLayout()); @@ -1737,12 +1744,19 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA myProgressIndicator, new Processor() { @Override public boolean process(Object o) { - if (isSymbol(o)) { - final PsiElement element = (PsiElement)o; - final PsiFile file = element.getContainingFile(); - if (!myListModel.contains(o) && !symbols.contains(o) && - //some elements are non-physical like DB columns - (file == null || (file.getVirtualFile() != null && (includeLibs || scope.accept(file.getVirtualFile()))))) { + if (SearchEverywhereClassifier.EP_Manager.isSymbol(o) && !myListModel.contains(o) && !symbols.contains(o)) { + PsiElement element = null; + if (o instanceof PsiElement) { + element = (PsiElement)o; + } + else if (o instanceof PsiElementNavigationItem) { + element = ((PsiElementNavigationItem)o).getTargetElement(); + } + VirtualFile virtualFile = SearchEverywhereClassifier.EP_Manager.getVirtualFile(o); + //some elements are non-physical like DB columns + boolean isElementWithoutFile = element != null && element.getContainingFile() == null; + boolean isFileInScope = virtualFile != null && (includeLibs || scope.accept(virtualFile)); + if (isElementWithoutFile || isFileInScope) { symbols.add(o); } } @@ -1758,16 +1772,6 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA return symbols; } - protected boolean isSymbol(Object o) { - if (o instanceof PsiElement) { - final PsiElement e = (PsiElement)o; - //todo[kb] need a better way to avoid mixing java classes with symbols. Same to other languages where - //todo[kb] symbol provider returns classes. We need kind of suppressor API & EP here. - return !e.getLanguage().is(Language.findLanguageByID("JAVA")) || !(e.getParent() instanceof PsiFile); - } - return false; - } - private SearchResult getClasses(String pattern, boolean includeLibs, final int max, ChooseByNamePopup chooseByNamePopup) { final SearchResult classes = new SearchResult(); if (chooseByNamePopup == null || shouldSkipPattern(pattern)) { @@ -1777,17 +1781,25 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA myProgressIndicator, new Processor() { @Override public boolean process(Object o) { - if (o instanceof PsiElement && !myListModel.contains(o) && !classes.contains(o)) { + if (SearchEverywhereClassifier.EP_Manager.isClass(o) && !myListModel.contains(o) && !classes.contains(o)) { if (classes.size() == max) { classes.needMore = true; return false; } + + PsiElement element = null; + if (o instanceof PsiElement) { + element = (PsiElement)o; + } + else if (o instanceof PsiElementNavigationItem) { + element = ((PsiElementNavigationItem)o).getTargetElement(); + } classes.add(o); - if (o instanceof PsiNamedElement) { - final String name = ((PsiNamedElement)o).getName(); - final PsiFile file = ((PsiNamedElement)o).getContainingFile(); - if (file != null) { - final VirtualFile virtualFile = file.getVirtualFile(); + + if (element instanceof PsiNamedElement) { + final String name = ((PsiNamedElement)element).getName(); + VirtualFile virtualFile = SearchEverywhereClassifier.EP_Manager.getVirtualFile(o); + if (virtualFile != null) { if (StringUtil.equals(name, virtualFile.getNameWithoutExtension())) { myAlreadyAddedFiles.add(virtualFile); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereClassifier.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereClassifier.java new file mode 100644 index 000000000000..7b9936f46166 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereClassifier.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.actions; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Philipp Smorygo + */ +public interface SearchEverywhereClassifier { + class EP_Manager { + private EP_Manager() {} + + public static boolean isClass(@Nullable Object o) { + for (SearchEverywhereClassifier classifier : Extensions.getExtensions(SearchEverywhereClassifier.EP_NAME)) { + if (classifier.isClass(o)) return true; + } + return false; + } + + public static boolean isSymbol(@Nullable Object o) { + for (SearchEverywhereClassifier classifier : Extensions.getExtensions(SearchEverywhereClassifier.EP_NAME)) { + if (classifier.isSymbol(o)) return true; + } + return false; + } + + @Nullable + public static VirtualFile getVirtualFile(@NotNull Object o) { + for (SearchEverywhereClassifier classifier : Extensions.getExtensions(SearchEverywhereClassifier.EP_NAME)) { + VirtualFile virtualFile = classifier.getVirtualFile(o); + if (virtualFile != null) return virtualFile; + } + return null; + } + + @Nullable + public static Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + for (SearchEverywhereClassifier classifier : Extensions.getExtensions(SearchEverywhereClassifier.EP_NAME)) { + Component component = classifier.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (component != null) return component; + } + return null; + } + } + + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.searchEverywhereClassifier"); + + boolean isClass(@Nullable Object o); + + boolean isSymbol(@Nullable Object o); + + @Nullable + VirtualFile getVirtualFile(@NotNull Object o); + + @Nullable + Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus); +} diff --git a/platform/lang-impl/src/com/intellij/ide/macro/FileDirPathFromParentMacro.java b/platform/lang-impl/src/com/intellij/ide/macro/FileDirPathFromParentMacro.java index eb68ae221082..c7a70bf1a4cb 100644 --- a/platform/lang-impl/src/com/intellij/ide/macro/FileDirPathFromParentMacro.java +++ b/platform/lang-impl/src/com/intellij/ide/macro/FileDirPathFromParentMacro.java @@ -18,9 +18,16 @@ package com.intellij.ide.macro; import com.intellij.ide.IdeBundle; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; public class FileDirPathFromParentMacro extends Macro { + + private static final String PATH_DELIMITER = "/"; + @Override public String getName() { return "FileDirPathFromParent"; @@ -41,13 +48,71 @@ public class FileDirPathFromParentMacro extends Macro { if(args.length == 0) { return super.expand(dataContext, args); } - String param = args[0]; - VirtualFile vFile = getVirtualDirOrParent(dataContext); - StringBuilder result = new StringBuilder(); - while (vFile != null && !param.equalsIgnoreCase(vFile.getName())) { - result.insert(0, vFile.getName() + "/"); - vFile = vFile.getParent(); + VirtualFile dir = getVirtualDirOrParent(dataContext); + if (dir == null) { + return ""; } - return result.toString(); + String dirPath = dir.getPath(); + String surroundedSubDir = surroundWithSlashes(FileUtil.toSystemIndependentName(args[0])); + String surroundedDirPath = surroundWithSlashes(dirPath); + if (surroundedSubDir.length() == 1) { + return surroundedDirPath.substring(1); + } + int ind = lastIndexOf(surroundedDirPath, + surroundedSubDir, + surroundedDirPath.length(), + !SystemInfo.isFileSystemCaseSensitive); + if (ind >= 0) { + return surroundedDirPath.substring(ind + surroundedSubDir.length()); + } + return dirPath.endsWith(PATH_DELIMITER) ? dirPath : dirPath + PATH_DELIMITER; + } + + private static int lastIndexOf(@NotNull CharSequence buffer, @NotNull String pattern, int maxIndex, boolean ignoreCase) { + int patternLength = pattern.length(); + int end = buffer.length() - patternLength; + if (maxIndex > end) { + maxIndex = end; + } + for (int i = maxIndex; i >= 0; i--) { + boolean found = true; + for (int j = 0; j < patternLength; j++) { + if (ignoreCase) { + if (!StringUtil.charsEqualIgnoreCase(pattern.charAt(j), buffer.charAt(i + j))) { + found = false; + break; + } + } + else { + if (pattern.charAt(j) != buffer.charAt(i + j)) { + found = false; + break; + } + } + } + if (found) { + return i; + } + } + return -1; + } + + @NotNull + private static String surroundWithSlashes(@NotNull String path) { + if (path.isEmpty()) { + return PATH_DELIMITER; + } + boolean prepend = !path.startsWith(PATH_DELIMITER); + boolean append = !path.endsWith(PATH_DELIMITER); + if (prepend && append) { + return PATH_DELIMITER + path + PATH_DELIMITER; + } + if (prepend) { + path = PATH_DELIMITER + path; + } + if (append) { + path += PATH_DELIMITER; + } + return path; } } diff --git a/platform/lang-impl/src/com/intellij/internal/DumpLookupElementWeights.java b/platform/lang-impl/src/com/intellij/internal/DumpLookupElementWeights.java index 40dce539f4ff..49e355c0a586 100644 --- a/platform/lang-impl/src/com/intellij/internal/DumpLookupElementWeights.java +++ b/platform/lang-impl/src/com/intellij/internal/DumpLookupElementWeights.java @@ -27,10 +27,12 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import java.awt.datatransfer.StringSelection; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -59,7 +61,7 @@ public class DumpLookupElementWeights extends AnAction implements DumbAware { if (selected != null) { sb += "\nprefix: " + lookup.itemPattern(selected); } - sb += "\nweights:\n" + StringUtil.join(getLookupElementWeights(lookup), "\n"); + sb += "\nweights:\n" + StringUtil.join(getLookupElementWeights(lookup, true), "\n"); System.out.println(sb); LOG.info(sb); try { @@ -67,15 +69,18 @@ public class DumpLookupElementWeights extends AnAction implements DumbAware { } catch (Exception ignore){} } - public static List getLookupElementWeights(LookupImpl lookup) { - final Map strings = lookup.getRelevanceStrings(); - List sb = new ArrayList(); - for (LookupElement item : lookup.getItems()) { - StringBuilder builder = strings.get(item); - String weight = builder == null ? "null" : builder.toString(); - final String s = item.getLookupString() + "\t" + weight; - sb.add(s); - } - return sb; + public static List getLookupElementWeights(LookupImpl lookup, boolean hideSingleValued) { + final Map>> weights = lookup.getRelevanceObjects(lookup.getItems(), hideSingleValued); + return ContainerUtil.map(weights.entrySet(), new Function>>, String>() { + @Override + public String fun(Map.Entry>> entry) { + return entry.getKey().getLookupString() + "\t" + StringUtil.join(entry.getValue(), new Function, String>() { + @Override + public String fun(Pair pair) { + return pair.first + "=" + pair.second; + } + }, ", "); + } + }); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/packageDependencies/ui/DirectoryNode.java b/platform/lang-impl/src/com/intellij/packageDependencies/ui/DirectoryNode.java index 7464c9f4cf48..6168269d7d98 100644 --- a/platform/lang-impl/src/com/intellij/packageDependencies/ui/DirectoryNode.java +++ b/platform/lang-impl/src/com/intellij/packageDependencies/ui/DirectoryNode.java @@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -116,14 +117,35 @@ public class DirectoryNode extends PackageDependenciesNode { public void fillFiles(Set set, boolean recursively) { super.fillFiles(set, recursively); int count = getChildCount(); + Boolean isRoot = null; for (int i = 0; i < count; i++) { PackageDependenciesNode child = (PackageDependenciesNode)getChildAt(i); if (child instanceof FileNode || recursively) { child.fillFiles(set, true); } + else if (child instanceof DirectoryNode) { + if (isRoot == null) { + isRoot = isContentOrSourceRoot(); + } + if (isRoot) { + child.fillFiles(set, false); + } + } } } + public boolean isContentOrSourceRoot() { + if (myVDirectory != null) { + final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); + final VirtualFile contentRoot = fileIndex.getContentRootForFile(myVDirectory); + final VirtualFile sourceRoot = fileIndex.getSourceRootForFile(myVDirectory); + if (myVDirectory.equals(contentRoot) || myVDirectory.equals(sourceRoot)) { + return true; + } + } + return false; + } + public String toString() { if (myFQName != null) return myFQName; if (myCompactPackages && myCompactedDirNode != null) { @@ -203,8 +225,9 @@ public class DirectoryNode extends PackageDependenciesNode { @Override public Icon getIcon() { - if (myDirectory != null) { - return new DirectoryIconProvider().getIcon(myDirectory, 0); + if (myVDirectory != null) { + final VirtualFile jarRoot = JarFileSystem.getInstance().getRootByEntry(myVDirectory); + return myVDirectory.equals(jarRoot) ? PlatformIcons.JAR_ICON : DirectoryIconProvider.getDirectoryIcon(myVDirectory, myProject); } return PlatformIcons.PACKAGE_ICON; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/file/DirectoryIconProvider.java b/platform/lang-impl/src/com/intellij/psi/impl/file/DirectoryIconProvider.java index 03e0b4fa4c92..1fa0d02c3c5f 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/file/DirectoryIconProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/file/DirectoryIconProvider.java @@ -43,20 +43,22 @@ public class DirectoryIconProvider extends IconProvider implements DumbAware { public Icon getIcon(@NotNull final PsiElement element, final int flags) { if (element instanceof PsiDirectory) { final PsiDirectory psiDirectory = (PsiDirectory)element; - final VirtualFile vFile = psiDirectory.getVirtualFile(); - Project project = psiDirectory.getProject(); - SourceFolder sourceFolder = ProjectRootsUtil.getModuleSourceRoot(vFile, project); - if (sourceFolder != null) { - return SourceRootPresentation.getSourceRootIcon(sourceFolder); - } - else { - Icon excludedIcon = getIconIfExcluded(project, vFile); - return excludedIcon != null ? excludedIcon : PlatformIcons.DIRECTORY_CLOSED_ICON; - } + return getDirectoryIcon(psiDirectory.getVirtualFile(), psiDirectory.getProject()); } return null; } + public static Icon getDirectoryIcon(VirtualFile vFile, Project project) { + SourceFolder sourceFolder = ProjectRootsUtil.getModuleSourceRoot(vFile, project); + if (sourceFolder != null) { + return SourceRootPresentation.getSourceRootIcon(sourceFolder); + } + else { + Icon excludedIcon = getIconIfExcluded(project, vFile); + return excludedIcon != null ? excludedIcon : PlatformIcons.DIRECTORY_CLOSED_ICON; + } + } + @Nullable public static Icon getIconIfExcluded(@NotNull Project project, @NotNull VirtualFile vFile) { if (!Registry.is("ide.hide.excluded.files")) { diff --git a/platform/lang-impl/testSources/com/intellij/ide/macro/MacroManagerTest.java b/platform/lang-impl/testSources/com/intellij/ide/macro/MacroManagerTest.java index 1e75aa12409e..316b9eb1f187 100644 --- a/platform/lang-impl/testSources/com/intellij/ide/macro/MacroManagerTest.java +++ b/platform/lang-impl/testSources/com/intellij/ide/macro/MacroManagerTest.java @@ -20,6 +20,7 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.actionSystem.impl.SimpleDataContext; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; @@ -37,7 +38,7 @@ public class MacroManagerTest extends CodeInsightFixtureTestCase { public DataContext getContext(VirtualFile file) { Project project = myFixture.getProject(); - Map dataId2data = new THashMap(); + Map dataId2data = new THashMap<>(); dataId2data.put(CommonDataKeys.PROJECT.getName(), project); dataId2data.put(CommonDataKeys.VIRTUAL_FILE.getName(), file); dataId2data.put(PlatformDataKeys.PROJECT_FILE_DIRECTORY.getName(), project.getBaseDir()); @@ -50,13 +51,28 @@ public class MacroManagerTest extends CodeInsightFixtureTestCase { "ans: $FileParentDir(bar)$ ", "ans: " + myFixture.getTempDirPath() + File.separator + "foo " ); - } - - public void testFileDirPathFromParentMacro() throws Throwable { doTest( - "foo/bar/baz/test.txt", + "foo/bar/baz/test2.txt", "ans: $FileDirPathFromParent(bar)$ ", "ans: baz/ " ); + doTest( + "foo/bar/baz/test3.txt", + "ans: $FileDirPathFromParent(foo/bar)$ ", + "ans: baz/ " + ); + doTest( + "foo/bar/baz/test4.txt", + "ans: $FileDirPathFromParent(foo/bar/baz/)$ ", + "ans: " + ); + } + + public void testFileDirPathFromParentMacro_NoParentFound() throws Throwable { + PsiFile file = myFixture.addFileToProject("foo/bar/baz/test.txt", ""); + String args = "ans: $FileDirPathFromParent(qqq/)$ "; + String actual = MacroManager.getInstance().expandMacrosInString(args, false, getContext(file.getVirtualFile())); + String expected = "ans: " + StringUtil.trimEnd(file.getVirtualFile().getParent().getPath(), "/") + "/ "; + assertEquals(expected, actual); } } diff --git a/platform/platform-impl/src/com/intellij/externalDependencies/impl/CheckRequiredPluginsActivity.java b/platform/platform-impl/src/com/intellij/externalDependencies/impl/CheckRequiredPluginsActivity.java index a85400460c81..782ec7a2ebef 100644 --- a/platform/platform-impl/src/com/intellij/externalDependencies/impl/CheckRequiredPluginsActivity.java +++ b/platform/platform-impl/src/com/intellij/externalDependencies/impl/CheckRequiredPluginsActivity.java @@ -71,11 +71,11 @@ public class CheckRequiredPluginsActivity implements StartupActivity, DumbAware } String minVersion = dependency.getMinVersion(); if (minVersion != null && VersionComparatorUtil.compare(plugin.getVersion(), minVersion) < 0) { - errorMessages.add("Project '" + project.getName() + "' requires '" + plugin.getName() + "' plugin of version at least '" + minVersion + "', but '" + plugin.getVersion() + "' is installed."); + errorMessages.add("Project '" + project.getName() + "' requires plugin '" + plugin.getName() + "' version '" + minVersion + "' or higher, but '" + plugin.getVersion() + "' is installed."); } String maxVersion = dependency.getMaxVersion(); if (maxVersion != null && VersionComparatorUtil.compare(plugin.getVersion(), maxVersion) > 0) { - errorMessages.add("Project '" + project.getName() + "' requires '" + plugin.getName() + "' plugin of version at most '" + maxVersion + "', but '" + plugin.getVersion() + "' is installed."); + errorMessages.add("Project '" + project.getName() + "' requires plugin '" + plugin.getName() + "' version '" + minVersion + "' or lower, but '" + plugin.getVersion() + "' is installed."); } } diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index c7eb78761a36..d8916bc6ce3b 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -483,15 +483,19 @@ public class IdeEventQueue extends EventQueue { modifiers |= InputEvent.ALT_MASK; } + int oldKeyCode = ke.getKeyCode(); + //noinspection MagicConstant - e = new KeyEvent(ke.getComponent(), ke.getID(), ke.getWhen(), modifiers, - ke.getKeyCode(), ke.getKeyChar(), ke.getKeyLocation()); + ke = new KeyEvent(ke.getComponent(), ke.getID(), ke.getWhen(), modifiers, + KeyEvent.VK_UNDEFINED, ke.getKeyChar(), KeyEvent.KEY_LOCATION_UNKNOWN); + + ke.setKeyCode(oldKeyCode); } } } } - return e; + return ke; } private static AWTEvent mapEvent(AWTEvent e) { diff --git a/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java b/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java index 9c23f46a9b0d..dea9ecaff2b7 100644 --- a/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java +++ b/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java @@ -54,7 +54,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class SystemHealthMonitor extends ApplicationComponent.Adapter { - private static final Logger LOG = Logger.getInstance("#com.intellij.ide.SystemHealthMonitor"); + private static final Logger LOG = Logger.getInstance(SystemHealthMonitor.class); private static final NotificationGroup GROUP = new NotificationGroup("System Health", NotificationDisplayType.STICKY_BALLOON, false); private static final NotificationGroup LOG_GROUP = NotificationGroup.logOnlyGroup("System Health (minor)"); @@ -112,9 +112,9 @@ public class SystemHealthMonitor extends ApplicationComponent.Adapter { private void showNotification(@PropertyKey(resourceBundle = "messages.IdeBundle") String key) { final String ignoreKey = "ignore." + key; - if (myProperties.isValueSet(ignoreKey)) { - return; - } + boolean ignored = myProperties.isValueSet(ignoreKey); + LOG.info("issue detected: " + key + (ignored ? " (ignored)" : "")); + if (ignored) return; final String message = IdeBundle.message(key) + IdeBundle.message("sys.health.acknowledge.link"); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java index c7947de91e53..6829bd8a09a1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java @@ -451,12 +451,14 @@ public class EditorActionUtil { int logLineEndOffset = document.getLineEndOffset(logLine); LogicalPosition logLineStart = editor.offsetToLogicalPosition(logLineStartOffset); VisualPosition visLineStart = editor.logicalToVisualPosition(logLineStart); + boolean newRendering = editor instanceof EditorImpl && ((EditorImpl)editor).myUseNewRendering; boolean softWrapIntroducedLine = visLineStart.line != visualLineNumber; if (!softWrapIntroducedLine) { int offset = findFirstNonSpaceOffsetInRange(document.getCharsSequence(), logLineStartOffset, logLineEndOffset); if (offset >= 0) { - return EditorUtil.calcColumnNumber(editor, document.getCharsSequence(), logLineStartOffset, offset); + return newRendering ? editor.offsetToVisualPosition(offset).column : + EditorUtil.calcColumnNumber(editor, document.getCharsSequence(), logLineStartOffset, offset); } else { return -1; @@ -491,6 +493,7 @@ public class EditorActionUtil { int end = findFirstNonSpaceOffsetInRange(softWrapText, j, softWrapTextLength); if (end >= 0) { + assert !newRendering : "Unexpected soft wrap text"; // Non space symbol is contained at soft wrap text after offset that corresponds to the target visual line start. if (nextSoftWrapLineFeedOffset < 0 || end < nextSoftWrapLineFeedOffset) { return EditorUtil.calcColumnNumber(editor, softWrapText, j, end); @@ -507,7 +510,8 @@ public class EditorActionUtil { } int end = findFirstNonSpaceOffsetInRange(document.getCharsSequence(), softWrap.getStart(), logLineEndOffset); if (end >= 0) { - return EditorUtil.calcColumnNumber(editor, document.getCharsSequence(), softWrap.getStart(), end); + return newRendering ? editor.offsetToVisualPosition(end).column : + EditorUtil.calcColumnNumber(editor, document.getCharsSequence(), softWrap.getStart(), end); } else { return -1; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 7b5f21a3ddf8..556dd39d4481 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -1832,6 +1832,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } private void bulkUpdateStarted() { + if (myUseNewRendering) { + myView.getPreferredSize(); // make sure size is calculated (in case it will be required while bulk mode is active) + } + saveCaretRelativePosition(); myCaretModel.onBulkDocumentUpdateStarted(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java index 84b06477b953..6f0f44d7d348 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FontInfo.java @@ -16,6 +16,7 @@ package com.intellij.openapi.editor.impl; import com.intellij.openapi.editor.ex.util.EditorUIUtil; +import com.intellij.openapi.editor.impl.view.FontLayoutService; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; import com.intellij.util.ui.UIUtil; @@ -188,7 +189,7 @@ public class FontInfo { public int charWidth(char c) { final FontMetrics metrics = fontMetrics(); if (c < 128) return charWidth[c]; - return metrics.charWidth(c); + return FontLayoutService.getInstance().charWidth(metrics, c); } private FontMetrics fontMetrics() { @@ -199,8 +200,8 @@ public class FontInfo { EditorUIUtil.setupAntialiasing(graphics); graphics.setFont(myFont); myFontMetrics = graphics.getFontMetrics(); - for (int i = 0; i < 128; i++) { - charWidth[i] = myFontMetrics.charWidth(i); + for (char c = 0; c < 128; c++) { + charWidth[c] = FontLayoutService.getInstance().charWidth(myFontMetrics, c); } } return myFontMetrics; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SettingsImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SettingsImpl.java index c675d490f072..3a98896d4bf4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SettingsImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SettingsImpl.java @@ -32,6 +32,7 @@ import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.PsiDocumentManager; @@ -355,7 +356,12 @@ public class SettingsImpl implements EditorSettings { } else { PsiFile file = getPsiFile(project); - tabSize = CodeStyleSettingsManager.getSettings(project).getIndentOptionsByFile(file).TAB_SIZE; + if (myEditor != null && myEditor.isViewer()) { + FileType fileType = file != null ? file.getFileType() : null; + tabSize = CodeStyleSettingsManager.getSettings(project).getIndentOptions(fileType).TAB_SIZE; + } else { + tabSize = CodeStyleSettingsManager.getSettings(project).getIndentOptionsByFile(file).TAB_SIZE; + } } myCachedTabSize = Integer.valueOf(tabSize); return tabSize; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java index 9718e1a2151c..690f11a41e72 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java @@ -627,7 +627,12 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedInternalDo if (!isSoftWrappingEnabled()) { return; } - executeSafely(myFoldProcessingEndTask); + if (myEditor.myUseNewRendering) { + myFoldProcessingEndTask.run(true); + } + else { + executeSafely(myFoldProcessingEndTask); + } } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/IncrementalCacheUpdateEvent.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/IncrementalCacheUpdateEvent.java index b59f48627323..1e638c951a54 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/IncrementalCacheUpdateEvent.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/IncrementalCacheUpdateEvent.java @@ -16,11 +16,11 @@ package com.intellij.openapi.editor.impl.softwrap.mapping; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.LogicalPosition; -import com.intellij.openapi.editor.VisualPosition; +import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.impl.EditorImpl; +import com.intellij.openapi.editor.impl.SoftWrapModelImpl; import org.jetbrains.annotations.NotNull; /** @@ -55,15 +55,15 @@ public class IncrementalCacheUpdateEvent { * @param event object that describes document change that caused cache update */ IncrementalCacheUpdateEvent(@NotNull DocumentEvent event, @NotNull CachingSoftWrapDataMapper mapper, @NotNull EditorImpl editor) { - this(event.getDocument(), event.getOffset(), event.getOffset() + event.getOldLength(), event.getOffset() + event.getNewLength(), mapper, editor); + this(event.getOffset(), event.getOffset() + event.getOldLength(), event.getOffset() + event.getNewLength(), mapper, editor); } /** * Creates new IncrementalCacheUpdateEvent object for the event not changing document length * (like expansion of folded region). */ - IncrementalCacheUpdateEvent(@NotNull Document document, int startOffset, int endOffset, @NotNull CachingSoftWrapDataMapper mapper, @NotNull EditorImpl editor) { - this(document, startOffset, endOffset, endOffset, mapper, editor); + IncrementalCacheUpdateEvent(int startOffset, int endOffset, @NotNull CachingSoftWrapDataMapper mapper, @NotNull EditorImpl editor) { + this(startOffset, endOffset, endOffset, mapper, editor); myNewEndLogicalLine = myOldEndLogicalLine; } @@ -82,22 +82,59 @@ public class IncrementalCacheUpdateEvent { myOldEndLogicalLine = myNewEndLogicalLine = Math.max(0, document.getLineCount() - 1); } - private IncrementalCacheUpdateEvent(@NotNull Document document, int startOffset, int oldEndOffset, int newEndOffset, + private IncrementalCacheUpdateEvent(int startOffset, int oldEndOffset, int newEndOffset, @NotNull CachingSoftWrapDataMapper mapper, @NotNull EditorImpl editor) { - myStartOffset = editor.myUseNewRendering ? editor.visualLineStartOffset(editor.offsetToVisualLine(startOffset) - 1) : - mapper.getPreviousVisualLineStartOffset(startOffset); - myMandatoryEndOffset = newEndOffset; - myLengthDiff = newEndOffset - oldEndOffset; - myStartLogicalPosition = editor.myUseNewRendering ? editor.offsetToLogicalPosition(myStartOffset) : - mapper.offsetToLogicalPosition(myStartOffset); if (editor.myUseNewRendering) { - myStartVisualPosition = editor.logicalToVisualPosition(myStartLogicalPosition); + VisualLineInfo info = getVisualLineInfo(editor, startOffset, false); + if (info.startsWithSoftWrap) { + info = getVisualLineInfo(editor, info.startOffset, true); + } + myStartOffset = info.startOffset; + myStartLogicalPosition = editor.offsetToLogicalPosition(myStartOffset); + myStartVisualPosition = new VisualPosition(info.visualLine, 0); } else { + myStartOffset = mapper.getPreviousVisualLineStartOffset(startOffset); + myStartLogicalPosition = mapper.offsetToLogicalPosition(myStartOffset); LOG.assertTrue(myStartLogicalPosition.visualPositionAware); myStartVisualPosition = myStartLogicalPosition.toVisualPosition(); } - myOldEndLogicalLine = document.getLineNumber(oldEndOffset); + myMandatoryEndOffset = newEndOffset; + myLengthDiff = newEndOffset - oldEndOffset; + myOldEndLogicalLine = editor.getDocument().getLineNumber(oldEndOffset); + } + + + private static VisualLineInfo getVisualLineInfo(@NotNull EditorImpl editor, int offset, boolean beforeSoftWrap) { + Document document = editor.getDocument(); + int textLength = document.getTextLength(); + if (offset <= 0 || textLength == 0) return new VisualLineInfo(0, 0, false); + offset = Math.min(offset, textLength); + + int startOffset = EditorUtil.getNotFoldedLineStartOffset(editor, offset); + + SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel(); + int wrapIndex = softWrapModel.getSoftWrapIndex(offset); + int prevSoftWrapIndex = wrapIndex < 0 ? (- wrapIndex - 2) : wrapIndex - (beforeSoftWrap ? 1 : 0); + SoftWrap prevSoftWrap = prevSoftWrapIndex < 0 ? null : softWrapModel.getRegisteredSoftWraps().get(prevSoftWrapIndex); + + int visualLine = document.getLineNumber(offset) - editor.getFoldingModel().getFoldedLinesCountBefore(offset) + (prevSoftWrapIndex + 1); + int visualLineStartOffset = prevSoftWrap == null ? startOffset : Math.max(startOffset, prevSoftWrap.getStart()); + return new VisualLineInfo(visualLine, + visualLineStartOffset, + prevSoftWrap != null && prevSoftWrap.getStart() == visualLineStartOffset); + } + + private static class VisualLineInfo { + private final int visualLine; + private final int startOffset; + private final boolean startsWithSoftWrap; + + private VisualLineInfo(int visualLine, int startOffset, boolean wrap) { + this.visualLine = visualLine; + this.startOffset = startOffset; + startsWithSoftWrap = wrap; + } } public void updateAfterDocumentChange(@NotNull Document document) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java index 3cfb4c336b19..49d7b9b1db0d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java @@ -193,8 +193,7 @@ public class SoftWrapApplianceManager implements Dumpable { for (Segment range : ranges) { int lastOffset = lastRecalculatedOffset[0]; if (range.getEndOffset() > lastOffset) { - recalculateSoftWraps(new IncrementalCacheUpdateEvent(myEditor.getDocument(), - Math.max(range.getStartOffset(), lastOffset), range.getEndOffset(), + recalculateSoftWraps(new IncrementalCacheUpdateEvent(Math.max(range.getStartOffset(), lastOffset), range.getEndOffset(), myDataMapper, myEditor)); } } @@ -240,8 +239,7 @@ public class SoftWrapApplianceManager implements Dumpable { LOG.error("Soft wrapping is not supported for documents with non-standard line endings. File: " + myEditor.getVirtualFile()); } if (myInProgress) { - LogMessageEx.error(LOG, "Detected race condition at soft wraps recalculation", - (myEditor instanceof EditorImpl) ? ((EditorImpl)myEditor).dumpState() : "", event.toString()); + LogMessageEx.error(LOG, "Detected race condition at soft wraps recalculation", myEditor.dumpState(), event.toString()); } myInProgress = true; try { @@ -459,10 +457,9 @@ public class SoftWrapApplianceManager implements Dumpable { int startOffset = myContext.currentPosition.offset; while (myContext.currentPosition.offset < myContext.tokenEndOffset) { if (counter++ > limit) { - String editorInfo = myEditor instanceof EditorImpl ? ((EditorImpl)myEditor).dumpState() : myEditor.getClass().toString(); LogMessageEx.error(LOG, "Cycled soft wraps recalculation detected", String.format( "Start recalculation offset: %d, visible area width: %d, calculation context: %s, editor info: %s", - startOffset, myVisibleAreaWidth, myContext, editorInfo)); + startOffset, myVisibleAreaWidth, myContext, myEditor.dumpState())); for (int i = myContext.currentPosition.offset; i < myContext.tokenEndOffset; i++) { char c = myContext.text.charAt(i); if (c == '\n') { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorSizeManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorSizeManager.java index b9ce1d8684f9..e41b3efc46a3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorSizeManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorSizeManager.java @@ -58,6 +58,11 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold private int myMaxLineWithExtensionWidth; private int myWidestLineWithExtension; + private int myDocumentChangeStartOffset; + private int myDocumentChangeEndOffset; + private int myFoldingChangeStartOffset = Integer.MAX_VALUE; + private int myFoldingChangeEndOffset = Integer.MIN_VALUE; + private final List myDeferredRanges = new ArrayList(); private final SoftWrapAwareDocumentParsingListenerAdapter mySoftWrapChangeListener = new SoftWrapAwareDocumentParsingListenerAdapter() { @@ -88,31 +93,34 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold @Override public void beforeDocumentChange(DocumentEvent event) { + if (myDocument.isInBulkUpdate()) return; + myDocumentChangeStartOffset = event.getOffset(); + myDocumentChangeEndOffset = event.getOffset() + event.getNewLength(); } @Override public void documentChanged(DocumentEvent event) { - invalidateRange(event.getOffset(), event.getOffset() + event.getNewLength()); + if (myDocument.isInBulkUpdate()) return; + doInvalidateRange(myDocumentChangeStartOffset, myDocumentChangeEndOffset); } - private int foldingChangeStartOffset = Integer.MAX_VALUE; - private int foldingChangeEndOffset = Integer.MIN_VALUE; - @Override public void onFoldRegionStateChange(@NotNull FoldRegion region) { + if (myDocument.isInBulkUpdate()) return; if (region.isValid()) { - foldingChangeStartOffset = Math.min(foldingChangeStartOffset, region.getStartOffset()); - foldingChangeEndOffset = Math.max(foldingChangeEndOffset, region.getEndOffset()); + myFoldingChangeStartOffset = Math.min(myFoldingChangeStartOffset, region.getStartOffset()); + myFoldingChangeEndOffset = Math.max(myFoldingChangeEndOffset, region.getEndOffset()); } } @Override public void onFoldProcessingEnd() { - if (foldingChangeStartOffset <= foldingChangeEndOffset) { - invalidateRange(foldingChangeStartOffset, foldingChangeEndOffset); + if (myDocument.isInBulkUpdate()) return; + if (myFoldingChangeStartOffset <= myFoldingChangeEndOffset) { + doInvalidateRange(myFoldingChangeStartOffset, myFoldingChangeEndOffset); } - foldingChangeStartOffset = Integer.MAX_VALUE; - foldingChangeEndOffset = Integer.MIN_VALUE; + myFoldingChangeStartOffset = Integer.MAX_VALUE; + myFoldingChangeEndOffset = Integer.MIN_VALUE; for (TextRange range : myDeferredRanges) { onTextLayoutPerformed(range.getStartOffset(), range.getEndOffset()); @@ -121,7 +129,21 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold } private void onSoftWrapRecalculationEnd(IncrementalCacheUpdateEvent event) { - invalidateRange(event.getStartOffset(), event.getActualEndOffset()); + if (myDocument.isInBulkUpdate()) return; + boolean invalidate = true; + if (myEditor.getFoldingModel().isInBatchFoldingOperation()) { + myFoldingChangeStartOffset = Math.min(myFoldingChangeStartOffset, event.getStartOffset()); + myFoldingChangeEndOffset = Math.max(myFoldingChangeEndOffset, event.getActualEndOffset()); + invalidate = false; + } + if (myDocument.isInEventsHandling()) { + myDocumentChangeStartOffset = Math.min(myDocumentChangeStartOffset, event.getStartOffset()); + myDocumentChangeEndOffset = Math.max(myDocumentChangeEndOffset, event.getActualEndOffset()); + invalidate = false; + } + if (invalidate) { + doInvalidateRange(event.getStartOffset(), event.getActualEndOffset()); + } } Dimension getPreferredSize() { @@ -149,6 +171,7 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold private int getPreferredWidth() { if (myWidthInPixels < 0) { + assert !myDocument.isInBulkUpdate(); myWidthInPixels = calculatePreferredWidth(); } validateMaxLineWithExtension(); @@ -193,10 +216,22 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold } void reset() { - invalidateRange(0, myDocument.getTextLength()); + assert !myDocument.isInBulkUpdate(); + doInvalidateRange(0, myDocument.getTextLength()); } void invalidateRange(int startOffset, int endOffset) { + if (myDocument.isInBulkUpdate()) return; + if (myDocument.isInEventsHandling()) { + myDocumentChangeStartOffset = Math.min(myDocumentChangeStartOffset, startOffset); + myDocumentChangeEndOffset = Math.max(myDocumentChangeEndOffset, endOffset); + } + else { + doInvalidateRange(startOffset, endOffset); + } + } + + private void doInvalidateRange(int startOffset, int endOffset) { myWidthInPixels = -1; int startVisualLine = myView.offsetToVisualLine(startOffset, false); int endVisualLine = myView.offsetToVisualLine(endOffset, true); @@ -223,6 +258,7 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold } void textLayoutPerformed(int startOffset, int endOffset) { + if (myDocument.isInBulkUpdate()) return; if (myEditor.getFoldingModel().isInBatchFoldingOperation()) { myDeferredRanges.add(new TextRange(startOffset, endOffset)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutDialog.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutDialog.java index b08cf0fdd087..e00bdf6f7f0c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutDialog.java @@ -15,260 +15,64 @@ */ package com.intellij.openapi.keymap.impl.ui; - -import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.KeyboardShortcut; -import com.intellij.openapi.actionSystem.ex.QuickList; -import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.keymap.KeyMapBundle; import com.intellij.openapi.keymap.Keymap; -import com.intellij.openapi.keymap.KeymapUtil; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.JBColor; -import com.intellij.ui.ScrollPaneFactory; -import com.intellij.util.ArrayUtil; import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Map; -import java.util.Set; +import java.awt.BorderLayout; +import java.awt.Component; +import java.util.Collection; +import javax.swing.JComponent; +import javax.swing.JPanel; -public class KeyboardShortcutDialog extends DialogWrapper { - private StrokePanel myFirstStrokePanel; - private StrokePanel mySecondStrokePanel; - private final JCheckBox myEnableSecondKeystroke; - private final JLabel myKeystrokePreview; - private final JTextArea myConflictInfoArea; - private Keymap myKeymap; - private final String myActionId; - private final Group myMainGroup; +/** + * @author Sergey.Malenkov + */ +final class KeyboardShortcutDialog extends ShortcutDialog { + private final JComponent myPreferredFocusedComponent; + + KeyboardShortcutDialog(Component parent) { + super(parent, "keyboard.shortcut.dialog.title", new KeyboardShortcutPanel(new BorderLayout())); + + KeyboardShortcutPanel panel = (KeyboardShortcutPanel)myShortcutPanel; + myPreferredFocusedComponent = panel.myFirstStroke; + + JPanel inner = new JPanel(new BorderLayout()); + inner.add(BorderLayout.CENTER, panel.mySecondStroke); + inner.add(BorderLayout.WEST, panel.mySecondStrokeEnable); + panel.add(BorderLayout.NORTH, panel.myFirstStroke); + panel.add(BorderLayout.SOUTH, inner); + panel.setBorder(JBUI.Borders.empty(0, 10)); + panel.mySecondStrokeEnable.setSelected(true); + panel.mySecondStrokeEnable.setText(KeyMapBundle.message("dialog.enable.second.stroke.checkbox")); - public KeyboardShortcutDialog(Component component, String actionId, final QuickList[] quickLists) { - super(component, true); - setTitle(KeyMapBundle.message("keyboard.shortcut.dialog.title")); - myActionId = actionId; - final Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(component)); - myMainGroup = ActionsTreeUtil.createMainGroup(project, myKeymap, quickLists, null, false, null); //without current filter - myEnableSecondKeystroke = new JCheckBox(); - UIUtil.applyStyle(UIUtil.ComponentStyle.SMALL, myEnableSecondKeystroke); - myEnableSecondKeystroke.setBorder(new EmptyBorder(4, 0, 0, 2)); - myEnableSecondKeystroke.setFocusable(false); - myKeystrokePreview = new JLabel(" "); - myConflictInfoArea = new JTextArea(""); - myConflictInfoArea.setFocusable(false); init(); } - @NotNull - protected Action[] createActions(){ - return new Action[]{getOKAction(),getCancelAction(),getHelpAction()}; + @Override + protected String getHelpId() { + return "preferences.keymap.shortcut"; } - protected JComponent createCenterPanel() { - JPanel panel = new JPanel(new GridBagLayout()); - - // First stroke - - myFirstStrokePanel = new StrokePanel(KeyMapBundle.message("first.stroke.panel.title")); - panel.add( - myFirstStrokePanel, - new GridBagConstraints(0,0,2,1,1,0,GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0) - ); - - // Second stroke panel - - panel.add( - myEnableSecondKeystroke, - new GridBagConstraints(0,1,1,1,0,0,GridBagConstraints.NORTHWEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0) - ); - - mySecondStrokePanel = new StrokePanel(KeyMapBundle.message("second.stroke.panel.title")); - panel.add( - mySecondStrokePanel, - new GridBagConstraints(1,1,1,1,1,0,GridBagConstraints.NORTHWEST,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0) - ); - - // Shortcut preview - - JPanel previewPanel = new JPanel(new BorderLayout()); - previewPanel.setBorder(IdeBorderFactory.createTitledBorder(KeyMapBundle.message("shortcut.preview.ide.border.factory.title"), true)); - previewPanel.add(myKeystrokePreview); - panel.add( - previewPanel, - new GridBagConstraints(0,2,2,1,1,0,GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0) - ); - - // Conflicts - - JPanel conflictsPanel = new JPanel(new BorderLayout()); - conflictsPanel.setBorder(IdeBorderFactory.createTitledBorder(KeyMapBundle.message("conflicts.ide.border.factory.title"), - true)); - myConflictInfoArea.setEditable(false); - myConflictInfoArea.setBackground(panel.getBackground()); - myConflictInfoArea.setLineWrap(true); - myConflictInfoArea.setWrapStyleWord(true); - final JScrollPane conflictInfoScroll = ScrollPaneFactory.createScrollPane(myConflictInfoArea); - conflictInfoScroll.setPreferredSize(JBUI.size(260, 60)); - conflictInfoScroll.setBorder(null); - conflictsPanel.add(conflictInfoScroll); - panel.add( - conflictsPanel, - new GridBagConstraints(0,3,2,1,1,1,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0) - ); - - myEnableSecondKeystroke.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleSecondKey(); - updateCurrentKeyStrokeInfo(); - - /** TODO[anton]???? */ - if (myEnableSecondKeystroke.isSelected()) { - mySecondStrokePanel.getShortcutTextField().requestFocus(); - } - else { - myFirstStrokePanel.getShortcutTextField().requestFocus(); - } - } - }); - return panel; + @Override + public JComponent getPreferredFocusedComponent() { + return myPreferredFocusedComponent; } - public JComponent getPreferredFocusedComponent(){ - return IdeFocusTraversalPolicy.getPreferredFocusedComponent(myFirstStrokePanel); + @Override + KeyboardShortcut toShortcut(Object value) { + return value instanceof KeyboardShortcut ? (KeyboardShortcut)value : null; } - public void setData(Keymap keymap, KeyboardShortcut shortcut) { - myKeymap = keymap; - myEnableSecondKeystroke.setSelected(false); - if (shortcut != null) { - myFirstStrokePanel.getShortcutTextField().setKeyStroke(shortcut.getFirstKeyStroke()); - if (shortcut.getSecondKeyStroke() != null) { - myEnableSecondKeystroke.setSelected(true); - mySecondStrokePanel.getShortcutTextField().setKeyStroke(shortcut.getSecondKeyStroke()); - } - } - handleSecondKey(); - updateCurrentKeyStrokeInfo(); + @Override + Collection getConflicts(KeyboardShortcut shortcut, String actionId, Keymap keymap) { + return keymap.getConflicts(actionId, shortcut).keySet(); } - private void updateCurrentKeyStrokeInfo() { - if (myConflictInfoArea == null || myKeystrokePreview == null){ - return; - } - - myConflictInfoArea.setText(null); - myKeystrokePreview.setText(" "); - - if (myKeymap == null){ - return; - } - - KeyboardShortcut keyboardShortcut = getKeyboardShortcut(); - if (keyboardShortcut == null){ - return; - } - - String strokeText = getTextByKeyStroke(keyboardShortcut.getFirstKeyStroke()); - String suffixText = getTextByKeyStroke(keyboardShortcut.getSecondKeyStroke()); - if(suffixText != null && suffixText.length() > 0) { - strokeText += ',' + suffixText; - } - myKeystrokePreview.setText(strokeText); - - StringBuilder buffer = new StringBuilder(); - - Map> conflicts = myKeymap.getConflicts(myActionId, keyboardShortcut); - - Set keys = conflicts.keySet(); - String[] actionIds = ArrayUtil.toStringArray(keys); - boolean loaded = true; - for (String actionId : actionIds) { - String actionPath = myMainGroup.getActionQualifiedPath(actionId); - if (actionPath == null) { - loaded = false; - } - if (buffer.length() > 1) { - buffer.append('\n'); - } - buffer.append('['); - buffer.append(actionPath != null ? actionPath : actionId); - buffer.append(']'); - } - - if (buffer.length() == 0) { - myConflictInfoArea.setForeground(UIUtil.getTextAreaForeground()); - myConflictInfoArea.setText(KeyMapBundle.message("no.conflict.info.message")); - } - else { - myConflictInfoArea.setForeground(JBColor.RED); - if (loaded) { - myConflictInfoArea.setText(KeyMapBundle.message("assigned.to.info.message", buffer.toString())); - } - else { - myConflictInfoArea.setText("Assigned to " + buffer.toString() + " which is now not loaded but may be loaded later"); - } - } - } - - private void handleSecondKey() { - mySecondStrokePanel.setEnabled(myEnableSecondKeystroke.isSelected()); - } - - @Nullable - public KeyboardShortcut getKeyboardShortcut() { - KeyStroke firstStroke = myFirstStrokePanel.getKeyStroke(); - return firstStroke == null ? null : new KeyboardShortcut(firstStroke, myEnableSecondKeystroke.isSelected() ? mySecondStrokePanel.getKeyStroke() : null); - } - - static String getTextByKeyStroke(KeyStroke keyStroke) { - if(keyStroke == null) { - return ""; - } - return KeymapUtil.getKeystrokeText(keyStroke); - } - - protected void doHelpAction() { - HelpManager.getInstance().invokeHelp("preferences.keymap.shortcut"); - } - - private class StrokePanel extends JPanel { - private final ShortcutTextField myShortcutTextField; - - public StrokePanel(String borderText) { - setLayout(new BorderLayout()); - setBorder(IdeBorderFactory.createTitledBorder(borderText, false)); - - myShortcutTextField = new ShortcutTextField(){ - protected void updateCurrentKeyStrokeInfo() { - KeyboardShortcutDialog.this.updateCurrentKeyStrokeInfo(); - } - }; - add(myShortcutTextField); - } - - public ShortcutTextField getShortcutTextField() { - return myShortcutTextField; - } - - public void setEnabled(boolean state) { - myShortcutTextField.setEnabled(state); - repaint(); - } - - public KeyStroke getKeyStroke() { - return myShortcutTextField.getKeyStroke(); - } + @Override + String getActionPath(String actionId) { + String actionPath = super.getActionPath(actionId); + return actionPath != null ? actionPath : actionId; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutPanel.java index 163b3975ca3a..982689937329 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeyboardShortcutPanel.java @@ -16,7 +16,6 @@ package com.intellij.openapi.keymap.impl.ui; import com.intellij.openapi.actionSystem.KeyboardShortcut; -import com.intellij.openapi.actionSystem.Shortcut; import java.awt.LayoutManager; import java.awt.event.ItemEvent; @@ -24,19 +23,16 @@ import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.JCheckBox; -import javax.swing.JPanel; import javax.swing.KeyStroke; /** * @author Sergey.Malenkov */ -final class KeyboardShortcutPanel extends JPanel { +final class KeyboardShortcutPanel extends ShortcutPanel { final ShortcutTextField myFirstStroke = new ShortcutTextField(); final ShortcutTextField mySecondStroke = new ShortcutTextField(); final JCheckBox mySecondStrokeEnable = new JCheckBox(); - private KeyboardShortcut myShortcut; - private final ItemListener myItemListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent event) { @@ -50,37 +46,35 @@ final class KeyboardShortcutPanel extends JPanel { private final PropertyChangeListener myPropertyListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { - setShortcut(newShortcut()); - if (null == myFirstStroke.getKeyStroke()) { - myFirstStroke.requestFocus(); + if (KeyboardShortcutPanel.this != event.getSource()) { + setShortcut(newShortcut()); + if (null == myFirstStroke.getKeyStroke()) { + myFirstStroke.requestFocus(); + } + else if (null == mySecondStroke.getKeyStroke() && mySecondStrokeEnable.isSelected()) { + mySecondStroke.requestFocus(); + } } - else if (null == mySecondStroke.getKeyStroke() && mySecondStrokeEnable.isSelected()) { - mySecondStroke.requestFocus(); + else if (event.getNewValue() instanceof KeyboardShortcut) { + KeyboardShortcut shortcut = (KeyboardShortcut)event.getNewValue(); + myFirstStroke.setKeyStroke(shortcut.getFirstKeyStroke()); + mySecondStroke.setKeyStroke(shortcut.getSecondKeyStroke()); + } + else { + myFirstStroke.setKeyStroke(null); + mySecondStroke.setKeyStroke(null); } } }; KeyboardShortcutPanel(LayoutManager layout) { super(layout); + addPropertyChangeListener("shortcut", myPropertyListener); myFirstStroke.addPropertyChangeListener("keyStroke", myPropertyListener); mySecondStroke.addPropertyChangeListener("keyStroke", myPropertyListener); mySecondStrokeEnable.addItemListener(myItemListener); } - KeyboardShortcut getShortcut() { - return myShortcut; - } - - void setShortcut(KeyboardShortcut shortcut) { - Shortcut old = myShortcut; - if (old == null || !old.equals(shortcut)) { - myShortcut = shortcut; - myFirstStroke.setKeyStroke(shortcut == null ? null : shortcut.getFirstKeyStroke()); - mySecondStroke.setKeyStroke(shortcut == null ? null : shortcut.getSecondKeyStroke()); - firePropertyChange("shortcut", old, shortcut); - } - } - private KeyboardShortcut newShortcut() { KeyStroke key = myFirstStroke.getKeyStroke(); return key == null ? null : new KeyboardShortcut(key, !mySecondStrokeEnable.isSelected() ? null : mySecondStroke.getKeyStroke()); diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java index eea7a96dab05..113703b4c9cd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java @@ -36,7 +36,6 @@ import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.ListPopup; @@ -468,40 +467,30 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi } private void addKeyboardShortcut(@NotNull String actionId, @Nullable Shortcut shortcut) { - Keymap keymap = createKeymapCopyIfNeeded(); - addKeyboardShortcut(actionId, shortcut, keymap, this, myQuickLists); + Keymap keymapSelected = myEditor.getModel().getSelected(); + assert keymapSelected != null; + addKeyboardShortcut(actionId, shortcut, keymapSelected, this, myQuickLists); repaintLists(); currentKeymapChanged(); } public static void addKeyboardShortcut(@NotNull String actionId, @Nullable Shortcut shortcut, - @NotNull Keymap keymap, + @NotNull Keymap keymapSelected, @NotNull Component parent, @NotNull QuickList[] quickLists) { - KeyboardShortcutDialog dialog = new KeyboardShortcutDialog(parent, actionId, quickLists); - dialog.setData(keymap, shortcut instanceof KeyboardShortcut ? (KeyboardShortcut)shortcut : null); - if (!dialog.showAndGet()) { - return; - } - - KeyboardShortcut keyboardShortcut = dialog.getKeyboardShortcut(); + KeyboardShortcutDialog dialog = new KeyboardShortcutDialog(parent); + KeyboardShortcut keyboardShortcut = dialog.showAndGet(shortcut, actionId, keymapSelected, quickLists); if (keyboardShortcut == null) { return; } - Map> conflicts = keymap.getConflicts(actionId, keyboardShortcut); - if (!conflicts.isEmpty()) { - int result = Messages.showYesNoCancelDialog( - parent, - KeyMapBundle.message("conflict.shortcut.dialog.message"), - KeyMapBundle.message("conflict.shortcut.dialog.title"), - KeyMapBundle.message("conflict.shortcut.dialog.remove.button"), - KeyMapBundle.message("conflict.shortcut.dialog.leave.button"), - KeyMapBundle.message("conflict.shortcut.dialog.cancel.button"), - Messages.getWarningIcon()); - + Keymap keymap = null; + if (dialog.hasConflicts()) { + int result = showConfirmationDialog(parent); if (result == Messages.YES) { + keymap = createKeymapCopyIfNeededAndPossible(parent, keymapSelected); + Map> conflicts = keymap.getConflicts(actionId, keyboardShortcut); for (String id : conflicts.keySet()) { for (KeyboardShortcut s : conflicts.get(id)) { keymap.removeShortcut(id, s); @@ -514,6 +503,8 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi } // if shortcut is already registered to this action, just select it in the list + + if (keymap == null) keymap = createKeymapCopyIfNeededAndPossible(parent, keymapSelected); Shortcut[] shortcuts = keymap.getShortcuts(actionId); for (Shortcut s : shortcuts) { if (s.equals(keyboardShortcut)) { @@ -533,40 +524,20 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi return; } - Keymap keymap = createKeymapCopyIfNeeded(); - - MouseShortcut mouseShortcut = shortcut instanceof MouseShortcut ? (MouseShortcut)shortcut : null; - Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(this)); - MouseShortcutDialog dialog = new MouseShortcutDialog( - this, - mouseShortcut, - keymap, - actionId, - ActionsTreeUtil.createMainGroup(project, keymap, myQuickLists, null, true, null), - restrictions - ); - if (!dialog.showAndGet()) { - return; - } - - mouseShortcut = dialog.getMouseShortcut(); + Keymap keymapSelected = myEditor.getModel().getSelected(); + MouseShortcutDialog dialog = new MouseShortcutDialog(this, restrictions.allowMouseDoubleClick); + MouseShortcut mouseShortcut = dialog.showAndGet(shortcut, actionId, keymapSelected, myQuickLists); if (mouseShortcut == null) { return; } - String[] actionIds = keymap.getActionIds(mouseShortcut); - if (actionIds.length > 1 || (actionIds.length == 1 && !actionId.equals(actionIds[0]))) { - int result = Messages.showYesNoCancelDialog( - this, - KeyMapBundle.message("conflict.shortcut.dialog.message"), - KeyMapBundle.message("conflict.shortcut.dialog.title"), - KeyMapBundle.message("conflict.shortcut.dialog.remove.button"), - KeyMapBundle.message("conflict.shortcut.dialog.leave.button"), - KeyMapBundle.message("conflict.shortcut.dialog.cancel.button"), - Messages.getWarningIcon()); - + Keymap keymap = null; + if (dialog.hasConflicts()) { + int result = showConfirmationDialog(this); if (result == Messages.YES) { + keymap = createKeymapCopyIfNeededAndPossible(this, keymapSelected); + String[] actionIds = keymap.getActionIds(mouseShortcut); for (String id : actionIds) { keymap.removeShortcut(id, mouseShortcut); } @@ -578,6 +549,7 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi // if shortcut is already registered to this action, just select it in the list + if (keymap == null) keymap = createKeymapCopyIfNeededAndPossible(this, keymapSelected); Shortcut[] shortcuts = keymap.getShortcuts(actionId); for (Shortcut shortcut1 : shortcuts) { if (shortcut1.equals(mouseShortcut)) { @@ -598,6 +570,15 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi myActionsTree.getComponent().repaint(); } + @NotNull + private static Keymap createKeymapCopyIfNeededAndPossible(Component parent, Keymap keymap) { + if (parent instanceof KeymapPanel) { + KeymapPanel panel = (KeymapPanel)parent; + keymap = panel.createKeymapCopyIfNeeded(); + } + return keymap; + } + @NotNull private Keymap createKeymapCopyIfNeeded() { Keymap keymap = myEditor.getModel().getSelected(); @@ -931,4 +912,15 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi return group; } + + private static int showConfirmationDialog(Component parent) { + return Messages.showYesNoCancelDialog( + parent, + KeyMapBundle.message("conflict.shortcut.dialog.message"), + KeyMapBundle.message("conflict.shortcut.dialog.title"), + KeyMapBundle.message("conflict.shortcut.dialog.remove.button"), + KeyMapBundle.message("conflict.shortcut.dialog.leave.button"), + KeyMapBundle.message("conflict.shortcut.dialog.cancel.button"), + Messages.getWarningIcon()); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutDialog.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutDialog.java index 2de4bdf5f3eb..fe0e21de9a4c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutDialog.java @@ -17,275 +17,68 @@ package com.intellij.openapi.keymap.impl.ui; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.MouseShortcut; -import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.openapi.keymap.KeyMapBundle; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapUtil; -import com.intellij.openapi.keymap.impl.ShortcutRestrictions; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.JBColor; -import com.intellij.ui.ScrollPaneFactory; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; -import org.intellij.lang.annotations.JdkConstants; -import org.jetbrains.annotations.NotNull; -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; +import java.awt.BorderLayout; +import java.awt.Component; +import java.util.Arrays; +import java.util.Collection; +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.SwingConstants; /** * @author Vladimir Kondratyev + * @author Sergey.Malenkov */ -class MouseShortcutDialog extends DialogWrapper{ - private final Keymap myKeymap; - private final String myActionId; - private final Group myMainGroup; +final class MouseShortcutDialog extends ShortcutDialog { + private final JLabel myText = new JLabel("", SwingConstants.CENTER); - private final JRadioButton myRbSingleClick; - private final JRadioButton myRbDoubleClick; - private final JLabel myLblPreview; - private final JLabel myClickPad; - private final JTextArea myTarConflicts; + MouseShortcutDialog(Component component, boolean allowDoubleClick) { + super(component, "mouse.shortcut.dialog.title", new MouseShortcutPanel(allowDoubleClick)); - private final MouseShortcutConsumer myShortcutConsumer; - - private int myButton; - @JdkConstants.InputEventMask private int myModifiers; - - /** - * @param shortcut dialog will be initialized with this shortcut. It can be null - * if dialog is used to create new mouse shortcut. - */ - public MouseShortcutDialog( - JComponent parentComponent, - MouseShortcut shortcut, - @NotNull Keymap keymap, - @NotNull String actiondId, - @NotNull Group mainGroup, - @NotNull ShortcutRestrictions restrictions - ){ - super(parentComponent,true); - setTitle(KeyMapBundle.message("mouse.shortcut.dialog.title")); - - myKeymap=keymap; - myActionId=actiondId; - myMainGroup=mainGroup; - - myRbSingleClick=new JRadioButton(KeyMapBundle.message("mouse.shortcut.dialog.single.click.radio")); - myRbDoubleClick=new JRadioButton(KeyMapBundle.message("mouse.shortcut.dialog.double.click.radio")); - ButtonGroup buttonGroup=new ButtonGroup(); - buttonGroup.add(myRbSingleClick); - buttonGroup.add(myRbDoubleClick); - - myLblPreview=new JLabel(" "); - - myTarConflicts=new JTextArea(); - myTarConflicts.setFocusable(false); - myTarConflicts.setEditable(false); - myTarConflicts.setBackground(UIUtil.getPanelBackground()); - myTarConflicts.setLineWrap(true); - myTarConflicts.setWrapStyleWord(true); - - if(shortcut!=null){ - if(shortcut.getClickCount()==1){ - myRbSingleClick.setSelected(true); - }else{ - myRbDoubleClick.setSelected(true); - } - myButton=shortcut.getButton(); - myModifiers=shortcut.getModifiers(); - }else{ - myRbSingleClick.setSelected(true); - myButton=-1; - myModifiers=-1; - } - - myRbDoubleClick.setEnabled(restrictions.allowMouseDoubleClick); - - updatePreviewAndConflicts(); - - myClickPad = new JLabel( - KeyMapBundle.message("mouse.shortcut.label"), - AllIcons.General.Mouse, SwingConstants.LEADING - ); - myShortcutConsumer = new MouseShortcutConsumer(shortcut) { - @Override - public void consume(MouseShortcut shortcut) { - myButton = shortcut.getButton(); - myModifiers = shortcut.getModifiers(); - updatePreviewAndConflicts(); - } - }; - myClickPad.addHierarchyListener(myShortcutConsumer); + myShortcutPanel.add(BorderLayout.NORTH, new JLabel(AllIcons.General.Mouse, SwingConstants.CENTER)); + myShortcutPanel.add(BorderLayout.CENTER, myText); + myShortcutPanel.setBorder(BorderFactory.createCompoundBorder( + JBUI.Borders.customLine(MouseShortcutPanel.BORDER, 1, 0, 1, 0), + JBUI.Borders.empty(20) + )); init(); } - /** - * @return created/edited shortcut. Returns null if shortcut is invalid. - */ - public MouseShortcut getMouseShortcut(){ - if (myButton > 3 && myButton != MouseShortcut.BUTTON_WHEEL_UP && myButton != MouseShortcut.BUTTON_WHEEL_DOWN && getClickCount() == 2) { - return null; - } - - if(myButton!=-1 && myModifiers!=-1){ - return new MouseShortcut(myButton,myModifiers,getClickCount()); - }else{ - return null; - } - } - @Override protected String getHelpId() { return "preferences.mouse.shortcut"; } - protected JComponent createCenterPanel(){ - JPanel panel=new JPanel(new GridBagLayout()); - - // Single/Double click - - JPanel clickCountPanel=new JPanel(new GridBagLayout()); - clickCountPanel.setBorder(IdeBorderFactory.createTitledBorder( - KeyMapBundle.message("mouse.shortcut.dialog.click.count.border"), true)); - panel.add( - clickCountPanel, - new GridBagConstraints(0,0,1,1,1,0,GridBagConstraints.CENTER,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0) - ); - clickCountPanel.add( - myRbSingleClick, - new GridBagConstraints(0,0,1,1,1,0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,10),0,0) - ); - clickCountPanel.add( - myRbDoubleClick, - new GridBagConstraints(1,0,1,1,1,0,GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0) - ); - - ActionListener listener=new ActionListener(){ - public void actionPerformed(ActionEvent e){ - updatePreviewAndConflicts(); - } - }; - myRbSingleClick.addActionListener(listener); - myRbDoubleClick.addActionListener(listener); - - // Click pad - - panel.add( - myClickPad, - new GridBagConstraints(0,1,1,1,1,0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,4,0),0,0) - ); - myClickPad.setBorder(BorderFactory.createCompoundBorder( - IdeBorderFactory.createTitledBorder(KeyMapBundle.message("mouse.shortcut.dialog.click.pad.border"), true), - JBUI.Borders.empty(20, 0, 20, 20))); - - // Shortcut preview - - JPanel previewPanel=new JPanel(new GridBagLayout()); - previewPanel.setBorder(IdeBorderFactory.createTitledBorder( - KeyMapBundle.message("mouse.shortcut.dialog.shortcut.preview.border"), true)); - panel.add( - previewPanel, - new GridBagConstraints(0,2,1,1,1,0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,4,0),0,0) - ); - previewPanel.add( - myLblPreview, - new GridBagConstraints(0,0,1,1,1,1,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(2,2,2,2),0,0) - ); - - // Conflicts panel - - JPanel conflictsPanel=new JPanel(new GridBagLayout()); - conflictsPanel.setBorder(IdeBorderFactory.createTitledBorder( - KeyMapBundle.message("mouse.shortcut.dialog.conflicts.border"), true)); - panel.add( - conflictsPanel, - new GridBagConstraints(0,3,1,1,1,1,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0) - ); - myTarConflicts.setPreferredSize(JBUI.size(260,60)); - JScrollPane scrollPane= ScrollPaneFactory.createScrollPane(myTarConflicts); - scrollPane.setBorder(null); - conflictsPanel.add( - scrollPane, - new GridBagConstraints(0,0,1,1,1,1,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0) - ); - - return panel; + @Override + MouseShortcut toShortcut(Object value) { + return value instanceof MouseShortcut ? (MouseShortcut)value : null; } - private int getClickCount() { - return myRbSingleClick.isSelected() ? 1 : 2; - } - /** - * Updates all UI controls - */ - private void updatePreviewAndConflicts(){ - if(myButton==-1||myModifiers==-1){ - return; - } - - myTarConflicts.setText(null); - - // Set text into preview area - - // empty string should have same height - myLblPreview.setText(KeymapUtil.getMouseShortcutText(myButton,myModifiers,getClickCount()) + " "); - - // Detect conflicts - - final MouseShortcut mouseShortcut=new MouseShortcut(myButton,myModifiers,getClickCount()); - - if (myButton > 3 && getClickCount() == 2) { - myTarConflicts.setForeground(JBColor.RED); - myTarConflicts.setText(KeyMapBundle.message("mouse.shortcut.dialog.side.buttons.with.double.click", myButton)); - return; - } - - StringBuilder buffer = new StringBuilder(); - String[] actionIds = myKeymap.getActionIds(mouseShortcut); - for (String actionId : actionIds) { - if (actionId.equals(myActionId)) { - continue; - } - - String actionPath = myMainGroup.getActionQualifiedPath(actionId); - // actionPath == null for editor actions having corresponding $-actions - if (actionPath == null) { - continue; - } - - Shortcut[] shortcuts = myKeymap.getShortcuts(actionId); - for (Shortcut shortcut1 : shortcuts) { - if (!(shortcut1 instanceof MouseShortcut)) { - continue; - } - - MouseShortcut shortcut = (MouseShortcut)shortcut1; - - if (shortcut.getButton() != mouseShortcut.getButton() || shortcut.getModifiers() != mouseShortcut.getModifiers()) { - continue; - } - - if (buffer.length() > 1) { - buffer.append('\n'); - } - buffer.append('['); - buffer.append(actionPath); - buffer.append(']'); - break; - } - } - - if (buffer.length() == 0) { - myTarConflicts.setForeground(UIUtil.getTextAreaForeground()); - myTarConflicts.setText(KeyMapBundle.message("mouse.shortcut.dialog.no.conflicts.area")); + @Override + void setShortcut(MouseShortcut shortcut) { + super.setShortcut(shortcut); + if (shortcut == null) { + myText.setForeground(MouseShortcutPanel.FOREGROUND); + myText.setText(KeyMapBundle.message("dialog.mouse.pad.default.text")); } else { - myTarConflicts.setForeground(JBColor.RED); - myTarConflicts.setText(KeyMapBundle.message("mouse.shortcut.dialog.assigned.to.area", buffer.toString())); + myText.setForeground(UIUtil.getLabelForeground()); + myText.setText(KeyMapBundle.message("dialog.mouse.pad.shortcut.text", KeymapUtil.getMouseShortcutText( + shortcut.getButton(), + shortcut.getModifiers(), + shortcut.getClickCount()))); } } + + @Override + Collection getConflicts(MouseShortcut shortcut, String actionId, Keymap keymap) { + return Arrays.asList(keymap.getActionIds(shortcut)); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutPanel.java index 0e0e6eeeebd2..a407bb780f65 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/MouseShortcutPanel.java @@ -22,18 +22,16 @@ import java.awt.BorderLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; -import javax.swing.JPanel; /** * @author Sergey.Malenkov */ -final class MouseShortcutPanel extends JPanel { +final class MouseShortcutPanel extends ShortcutPanel { static final JBColor FOREGROUND = new JBColor(0x8C8C8C, 0x8C8C8C); static final JBColor BACKGROUND = new JBColor(0xF5F5F5, 0x4B4F52); static final JBColor BORDER = new JBColor(0xDEDEDE, 0x383B3D); - private MouseShortcut myShortcut; - + private final int myClickCount; private final MouseAdapter myMouseListener = new MouseAdapter() { @Override public void mouseWheelMoved(MouseWheelEvent event) { @@ -46,35 +44,26 @@ final class MouseShortcutPanel extends JPanel { int button = MouseShortcut.getButton(event); int clickCount = event instanceof MouseWheelEvent ? 1 : event.getClickCount(); - if (0 <= button && clickCount < 3) { + if (0 <= button && clickCount <= myClickCount) { int modifiers = event.getModifiersEx(); - if (myShortcut == null - || button != myShortcut.getButton() - || modifiers != myShortcut.getModifiers() - || clickCount != myShortcut.getClickCount()) { - setShortcut(new MouseShortcut(button, modifiers, clickCount)); - } + setShortcut(new MouseShortcut(button, modifiers, clickCount)); } } }; - MouseShortcutPanel() { + MouseShortcutPanel(boolean allowDoubleClick) { super(new BorderLayout()); + myClickCount = allowDoubleClick ? 2 : 1; addMouseListener(myMouseListener); addMouseWheelListener(myMouseListener); setBackground(BACKGROUND); setOpaque(true); } - MouseShortcut getShortcut() { - return myShortcut; - } - void setShortcut(MouseShortcut shortcut) { - MouseShortcut old = myShortcut; + MouseShortcut old = getShortcut(); if (old != null || shortcut != null) { - myShortcut = shortcut; - firePropertyChange("shortcut", old, shortcut); + super.setShortcut(shortcut); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java new file mode 100644 index 000000000000..b0713fe96cfc --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java @@ -0,0 +1,189 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.keymap.impl.ui; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.Shortcut; +import com.intellij.openapi.actionSystem.ex.QuickList; +import com.intellij.openapi.keymap.KeyMapBundle; +import com.intellij.openapi.keymap.Keymap; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.SimpleColoredComponent; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.ui.components.GradientViewport; +import com.intellij.ui.components.JBPanel; +import com.intellij.ui.components.panels.VerticalLayout; +import com.intellij.util.ui.ButtonlessScrollBarUI; +import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.Nullable; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Collection; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingConstants; +import javax.swing.border.Border; + +/** + * @author Sergey.Malenkov + */ +abstract class ShortcutDialog extends DialogWrapper { + private final SimpleColoredComponent myAction = new SimpleColoredComponent(); + private final JBPanel myConflictsContainer = new JBPanel(new VerticalLayout(0)); + private final JBPanel myConflictsPanel = new JBPanel(new BorderLayout()) + .withBorder(JBUI.Borders.empty(5, 10, 0, 10)) + .withPreferredHeight(64) + .withMinimumHeight(64); + + protected final ShortcutPanel myShortcutPanel; + private final Project myProject; + private String myActionId; + private Keymap myKeymap; + private Group myGroup; + + ShortcutDialog(Component parent, String title, ShortcutPanel panel) { + super(parent, true); + myShortcutPanel = panel; + myProject = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(parent)); + setTitle(KeyMapBundle.message(title)); + } + + String getActionPath(String actionId) { + return myGroup == null ? null : myGroup.getActionQualifiedPath(actionId); + } + + boolean hasConflicts() { + return myConflictsPanel.isVisible(); + } + + abstract Collection getConflicts(T shortcut, String actionId, Keymap keymap); + + abstract T toShortcut(Object value); + + void setShortcut(T shortcut) { + if (!equal(shortcut, myShortcutPanel.getShortcut())) { + myShortcutPanel.setShortcut(shortcut); + } + myConflictsContainer.removeAll(); + if (shortcut != null) { + for (String id : getConflicts(shortcut, myActionId, myKeymap)) { + String path = id.equals(myActionId) ? null : getActionPath(id); + if (path != null) { + SimpleColoredComponent component = new SimpleColoredComponent(); + fill(component, id, path); + myConflictsContainer.add(VerticalLayout.TOP, component); + } + } + myConflictsPanel.revalidate(); + } + myConflictsPanel.setVisible(0 < myConflictsContainer.getComponentCount()); + } + + T showAndGet(Shortcut shortcut, String id, Keymap keymap, QuickList... lists) { + myActionId = id; + myKeymap = keymap; + myGroup = ActionsTreeUtil.createMainGroup(myProject, keymap, lists, null, false, null); + fill(myAction, id, getActionPath(id)); + setShortcut(toShortcut(shortcut)); + return showAndGet() ? myShortcutPanel.getShortcut() : null; + } + + @Nullable + @Override + protected Border createContentPaneBorder() { + return JBUI.Borders.empty(); + } + + @Nullable + @Override + protected JComponent createSouthPanel() { + JComponent panel = super.createSouthPanel(); + if (panel != null) { + panel.setBorder(JBUI.Borders.empty(8, 12)); + } + return panel; + } + + @Nullable + @Override + protected JComponent createNorthPanel() { + myAction.setIpad(JBUI.insets(10, 10, 5, 10)); + myShortcutPanel.addPropertyChangeListener("shortcut", new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent event) { + setShortcut(toShortcut(event.getNewValue())); + } + }); + JBPanel result = new JBPanel(new BorderLayout()).withPreferredWidth(300).withMinimumWidth(200); + result.add(BorderLayout.NORTH, myAction); + result.add(BorderLayout.SOUTH, myShortcutPanel); + return result; + } + + @Override + protected JComponent createCenterPanel() { + JLabel icon = new JLabel(AllIcons.General.BalloonWarning); + icon.setVerticalAlignment(SwingConstants.TOP); + + JLabel label = new JLabel(KeyMapBundle.message("dialog.conflicts.text")); + label.setBorder(JBUI.Borders.emptyLeft(2)); + + JScrollPane scroll = ScrollPaneFactory.createScrollPane(null, true); + scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + scroll.setViewport(new GradientViewport(myConflictsContainer, JBUI.insets(5), false)); + scroll.getVerticalScrollBar().setUI(ButtonlessScrollBarUI.createTransparent()); + scroll.getVerticalScrollBar().setUnitIncrement(JBUI.scale(10)); + + JBPanel panel = new JBPanel(new BorderLayout()); + panel.add(BorderLayout.NORTH, label); + panel.add(BorderLayout.CENTER, scroll); + + myConflictsPanel.add(BorderLayout.WEST, icon); + myConflictsPanel.add(BorderLayout.CENTER, panel); + myConflictsContainer.setOpaque(false); + return myConflictsPanel; + } + + private static boolean equal(Shortcut newShortcut, Shortcut oldShortcut) { + return newShortcut == null ? oldShortcut == null : newShortcut.equals(oldShortcut); + } + + private static void fill(SimpleColoredComponent component, String id, String path) { + if (path == null) { + component.append(id, SimpleTextAttributes.REGULAR_ITALIC_ATTRIBUTES); + } + else { + int index = path.lastIndexOf(" | "); + if (index < 0) { + component.append(path, SimpleTextAttributes.REGULAR_ATTRIBUTES); + } + else { + component.append(path.substring(index + 3), SimpleTextAttributes.REGULAR_ATTRIBUTES); + component.append(" in ", SimpleTextAttributes.GRAYED_ATTRIBUTES); + component.append(path.substring(0, index), SimpleTextAttributes.GRAYED_ATTRIBUTES); + } + } + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutFilteringPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutFilteringPanel.java index 6e3b199eade5..ccedfc13be04 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutFilteringPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutFilteringPanel.java @@ -40,7 +40,7 @@ import javax.swing.event.ChangeListener; */ final class ShortcutFilteringPanel extends JPanel { final KeyboardShortcutPanel myKeyboardPanel = new KeyboardShortcutPanel(new VerticalLayout(JBUI.scale(2))); - final MouseShortcutPanel myMousePanel = new MouseShortcutPanel(); + final MouseShortcutPanel myMousePanel = new MouseShortcutPanel(true); private Shortcut myShortcut; private JBPopup myPopup; diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutPanel.java new file mode 100644 index 000000000000..1cad3154f95b --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutPanel.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.keymap.impl.ui; + +import com.intellij.openapi.actionSystem.Shortcut; + +import java.awt.LayoutManager; +import javax.swing.JPanel; + +/** + * @author Sergey.Malenkov + */ +class ShortcutPanel extends JPanel { + private T myShortcut; + + ShortcutPanel(LayoutManager layout) { + super(layout); + } + + T getShortcut() { + return myShortcut; + } + + void setShortcut(T shortcut) { + T old = myShortcut; + myShortcut = shortcut; + firePropertyChange("shortcut", old, shortcut); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java index b35a096fd51d..fa7f6787ac3f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java @@ -31,10 +31,10 @@ import javax.swing.text.DefaultCaret; import java.awt.*; import java.awt.event.KeyEvent; -public class ShortcutTextField extends JTextField { +public final class ShortcutTextField extends JTextField { private KeyStroke myKeyStroke; - public ShortcutTextField() { + ShortcutTextField() { enableEvents(AWTEvent.KEY_EVENT_MASK); setFocusTraversalKeysEnabled(false); putClientProperty("JTextField.variant", "search"); @@ -62,21 +62,17 @@ public class ShortcutTextField extends JTextField { } } - public void setKeyStroke(KeyStroke keyStroke) { + void setKeyStroke(KeyStroke keyStroke) { KeyStroke old = myKeyStroke; if (old != null || keyStroke != null) { myKeyStroke = keyStroke; super.setText(KeymapUtil.getKeystrokeText(keyStroke)); setCaretPosition(0); - updateCurrentKeyStrokeInfo(); firePropertyChange("keyStroke", old, keyStroke); } } - protected void updateCurrentKeyStrokeInfo() { - } - - public KeyStroke getKeyStroke() { + KeyStroke getKeyStroke() { return myKeyStroke; } diff --git a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java index 788864eaabb4..a1d1cc15b81e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java @@ -151,14 +151,14 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica @Override public void runWhenSmart(@NotNull Runnable runnable) { - if (!isDumb()) { - runnable.run(); - } - else { - synchronized (myRunWhenSmartQueue) { + synchronized (myRunWhenSmartQueue) { + if (isDumb()) { myRunWhenSmartQueue.addLast(runnable); + return; } } + + runnable.run(); } private void scheduleCacheUpdate(@NotNull final DumbModeTask task, boolean forceDumbMode) { @@ -220,7 +220,9 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica application.runWriteAction(new Runnable() { @Override public void run() { - myDumb = true; + synchronized (myRunWhenSmartQueue) { + myDumb = true; + } myDumbStart = trace; myModificationCount++; try { @@ -286,7 +288,9 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica } private void updateFinished(boolean modal) { - myDumb = false; + synchronized (myRunWhenSmartQueue) { + myDumb = false; + } myDumbStart = null; myModificationCount++; if (myProject.isDisposed()) return; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.java index 5a45cf7898ac..15143b8480d5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeRootPane.java @@ -38,6 +38,7 @@ import com.intellij.openapi.wm.impl.status.MemoryUsagePanel; import com.intellij.ui.BalloonLayout; import com.intellij.ui.BalloonLayoutImpl; import com.intellij.ui.PopupHandler; +import com.intellij.ui.ScreenUtil; import com.intellij.ui.components.JBLayeredPane; import com.intellij.ui.components.JBPanel; import com.intellij.util.containers.ContainerUtil; @@ -147,7 +148,9 @@ public class IdeRootPane extends JRootPane implements UISettingsListener { */ public final void removeNotify(){ myUISettings.removeUISettingsListener(this); - removeToolbar(); + if (ScreenUtil.isStandardAddRemoveNotify(this)) { + removeToolbar(); + } super.removeNotify(); } 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 41885d1cd823..5f4cc4b91363 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 @@ -85,8 +85,6 @@ import java.beans.PropertyChangeListener; import java.util.*; import java.util.List; -import static com.intellij.openapi.wm.impl.FloatingDecorator.DIVIDER_WIDTH; - /** * @author Anton Katilin * @author Vladimir Kondratyev @@ -975,7 +973,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements deactivateToolWindowImpl(id, true, commandList); - if (hideSide && !info.isFloating()) { + if (hideSide && !info.isFloating() && !info.isWindowed()) { final List ids = myLayout.getVisibleIdsOn(info.getAnchor(), this); for (String each : ids) { myActiveStack.remove(each, true); @@ -2091,7 +2089,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements private final FloatingDecorator myFloatingDecorator; /** - * Creates floating decorator for specified floating decorator. + * Creates floating decorator for specified internal decorator. */ private AddFloatingDecoratorCmd(final InternalDecorator decorator, final WindowInfoImpl info) { super(myWindowManager.getCommandProcessor()); @@ -2163,16 +2161,13 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements private final WindowedDecorator myWindowedDecorator; /** - * Creates floating decorator for specified floating decorator. + * Creates windowed decorator for specified internal decorator. */ private AddWindowedDecoratorCmd(final InternalDecorator decorator, final WindowInfoImpl info) { super(myWindowManager.getCommandProcessor()); myWindowedDecorator = new WindowedDecorator(myProject, info.copy(), decorator); Window window = myWindowedDecorator.getFrame(); final Rectangle bounds = info.getFloatingBounds(); - if (bounds != null) { - bounds.setBounds(bounds.x + DIVIDER_WIDTH, bounds.y + DIVIDER_WIDTH, bounds.width - 2 * DIVIDER_WIDTH, bounds.height - 2 * DIVIDER_WIDTH); - } if (bounds != null && bounds.width > 0 && bounds.height > 0 && @@ -2230,10 +2225,10 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements myWindowedDecorator = getWindowedDecorator(info.getId()); myId2WindowedDecorator.remove(info.getId()); - JRootPane rootPane = ((RootPaneContainer)myWindowedDecorator.getFrame()).getRootPane(); - Rectangle bounds = rootPane.getBounds(); - Point location = rootPane.getLocationOnScreen(); - bounds.setBounds(location.x - DIVIDER_WIDTH, location.y - DIVIDER_WIDTH, bounds.width + 2 * DIVIDER_WIDTH, bounds.height + 2 * DIVIDER_WIDTH); + Window frame = myWindowedDecorator.getFrame(); + if (!frame.isShowing()) return; + Rectangle bounds = frame.getBounds(); + bounds.setLocation(frame.getLocationOnScreen()); info.setFloatingBounds(bounds); } diff --git a/platform/platform-resources-en/src/messages/KeyMapBundle.properties b/platform/platform-resources-en/src/messages/KeyMapBundle.properties index 29986a28f522..010c44825ea7 100644 --- a/platform/platform-resources-en/src/messages/KeyMapBundle.properties +++ b/platform/platform-resources-en/src/messages/KeyMapBundle.properties @@ -96,6 +96,11 @@ mouse.wheel.rotate.down.shortcut.text={0}Wheel down configuration.all.keymaps.should.have.non.empty.names.error.message=All keymaps should have non empty names configuration.all.keymaps.should.have.unique.names.error.message=All keymaps should have unique names +dialog.enable.second.stroke.checkbox=Second stroke: +dialog.mouse.pad.default.text=
Enter a shortcut here:
single or double-click, scroll the wheel,
modify with Ctrl, Alt and Shift +dialog.mouse.pad.shortcut.text=

{0}

+dialog.conflicts.text=Already assigned to: + filter.clear.action.text=Clear Filtering filter.settings.popup.title=Find Shortcut filter.enable.second.stroke.checkbox=Second stroke diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index b2ec46225bdc..ac297d36c338 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -843,6 +843,7 @@ + diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 6f1691dbb1c3..5a9b04f6555a 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -557,6 +557,7 @@ + diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java index ebc3a285bc2a..9b1fc12e031f 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java @@ -199,4 +199,11 @@ public class EditorImplTest extends AbstractEditorTest { myEditor.getSettings().setAdditionalLinesCount(0); assertEquals(new Dimension(50, 30), myEditor.getContentComponent().getPreferredSize()); } + + public void testCollapsingRegionContainingSoftWrap() throws Exception { + initText("abcdef abcdef"); + configureSoftWraps(10); + addCollapsedFoldRegion(0, 13, "..."); + assertEquals(new VisualPosition(0, 3), myEditor.offsetToVisualPosition(13)); + } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorStressTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorStressTest.java new file mode 100644 index 000000000000..a51e8153217c --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorStressTest.java @@ -0,0 +1,200 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.impl; + +import com.intellij.openapi.editor.*; +import com.intellij.openapi.editor.ex.DocumentEx; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.ex.SoftWrapModelEx; +import com.intellij.util.DocumentUtil; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +public class EditorStressTest extends AbstractEditorTest { + private static final int ITERATIONS = 10000; + private static final Long SEED_OVERRIDE = null; // set non-null value to run with a specific seed + + private static final List ourActions = Arrays.asList(new AddText("a"), + new AddText("\n"), + new AddText("\t"), + new RemoveCharacter(), + new MoveCharacter(), + new AddFoldRegion(), + new RemoveFoldRegion(), + new CollapseFoldRegion(), + new ExpandFoldRegion(), + new ChangeBulkModeState()); + + private final Random myRandom = new Random() {{ + //noinspection ConstantConditions + setSeed(mySeed = (SEED_OVERRIDE == null ? nextLong() : SEED_OVERRIDE)); + }}; + private long mySeed; + + public void testRandomActions() { + int i = 0; + try { + initText(""); + configureSoftWraps(10); + for (i = 1; i <= ITERATIONS; i++) { + doRandomAction(); + checkConsistency(myEditor); + } + } + catch (Throwable t) { + String message = "Failed when run with seed=" + mySeed + " in iteration " + i; + System.out.println(message); + throw new RuntimeException(message, t); + } + } + + private void doRandomAction() { + ourActions.get(myRandom.nextInt(ourActions.size())).perform(myEditor, myRandom); + } + + protected void checkConsistency(Editor editor) { + checkSoftWrapPositions(editor); + } + + private static void checkSoftWrapPositions(Editor editor) { + DocumentEx document = ((EditorEx)editor).getDocument(); + if (document.isInBulkUpdate()) return; + FoldingModel foldingModel = editor.getFoldingModel(); + List softWraps = ((SoftWrapModelEx)editor.getSoftWrapModel()).getRegisteredSoftWraps(); + int lastSoftWrapOffset = -1; + for (SoftWrap wrap : softWraps) { + int softWrapOffset = wrap.getStart(); + assertTrue("Soft wraps are not ordered", softWrapOffset > lastSoftWrapOffset); + FoldRegion foldRegion = foldingModel.getCollapsedRegionAtOffset(softWrapOffset); + assertTrue("Soft wrap is inside fold region", foldRegion == null || foldRegion.getStartOffset() == softWrapOffset); + assertFalse("Soft wrap before line break", softWrapOffset == DocumentUtil.getLineEndOffset(softWrapOffset, document) && + foldRegion == null); + assertFalse("Soft wrap after line break", softWrapOffset == DocumentUtil.getLineStartOffset(softWrapOffset, document) && + !foldingModel.isOffsetCollapsed(softWrapOffset - 1)); + lastSoftWrapOffset = softWrapOffset; + } + } + + interface Action { + void perform(Editor editor, Random random); + } + + private static class AddText implements Action { + private final String myText; + + AddText(String text) { + myText = text; + } + + @Override + public void perform(Editor editor, Random random) { + Document document = editor.getDocument(); + int offset = random.nextInt(document.getTextLength() + 1); + document.insertString(offset, myText); + } + } + + private static class RemoveCharacter implements Action { + @Override + public void perform(Editor editor, Random random) { + Document document = editor.getDocument(); + int textLength = document.getTextLength(); + if (textLength <= 0) return; + int offset = random.nextInt(textLength); + document.deleteString(offset, offset + 1); + } + } + + private static class MoveCharacter implements Action { + @Override + public void perform(Editor editor, Random random) { + Document document = editor.getDocument(); + int textLength = document.getTextLength(); + if (textLength <= 0) return; + int offset = random.nextInt(textLength); + int targetOffset = random.nextInt(textLength + 1); + if (targetOffset < offset || targetOffset > offset + 1) { + ((DocumentEx)document).moveText(offset, offset + 1, targetOffset); + } + } + } + + private static class AddFoldRegion implements Action { + @Override + public void perform(final Editor editor, Random random) { + DocumentEx document = ((EditorEx)editor).getDocument(); + if (document.isInBulkUpdate()) return; + int textLength = document.getTextLength(); + if (textLength <= 0) return; + final int startOffset = random.nextInt(textLength + 1); + final int endOffset = random.nextInt(textLength + 1); + if (startOffset == endOffset) return; + final FoldingModel foldingModel = editor.getFoldingModel(); + foldingModel.runBatchFoldingOperation(() -> foldingModel.addFoldRegion(Math.min(startOffset, endOffset), + Math.max(startOffset, endOffset), + ".")); + } + } + + private static class RemoveFoldRegion implements Action { + @Override + public void perform(final Editor editor, Random random) { + DocumentEx document = ((EditorEx)editor).getDocument(); + if (document.isInBulkUpdate()) return; + final FoldingModel foldingModel = editor.getFoldingModel(); + FoldRegion[] foldRegions = foldingModel.getAllFoldRegions(); + if (foldRegions.length == 0) return; + final FoldRegion region = foldRegions[random.nextInt(foldRegions.length)]; + foldingModel.runBatchFoldingOperation(() -> foldingModel.removeFoldRegion(region)); + } + } + + private static class CollapseFoldRegion implements Action { + @Override + public void perform(final Editor editor, Random random) { + DocumentEx document = ((EditorEx)editor).getDocument(); + if (document.isInBulkUpdate()) return; + final FoldingModel foldingModel = editor.getFoldingModel(); + FoldRegion[] foldRegions = foldingModel.getAllFoldRegions(); + if (foldRegions.length == 0) return; + final FoldRegion region = foldRegions[random.nextInt(foldRegions.length)]; + foldingModel.runBatchFoldingOperation(() -> region.setExpanded(false)); + } + } + + private static class ExpandFoldRegion implements Action { + @Override + public void perform(final Editor editor, Random random) { + DocumentEx document = ((EditorEx)editor).getDocument(); + if (document.isInBulkUpdate()) return; + final FoldingModel foldingModel = editor.getFoldingModel(); + FoldRegion[] foldRegions = foldingModel.getAllFoldRegions(); + if (foldRegions.length == 0) return; + final FoldRegion region = foldRegions[random.nextInt(foldRegions.length)]; + foldingModel.runBatchFoldingOperation(() -> region.setExpanded(true)); + } + } + + private static class ChangeBulkModeState implements Action { + @Override + public void perform(Editor editor, Random random) { + DocumentEx document = ((EditorEx)editor).getDocument(); + document.setInBulkUpdate(!document.isInBulkUpdate()); + } + } +} \ No newline at end of file diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapStressTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapStressTest.java index fdc7acd86bdb..692a32b3a609 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapStressTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapStressTest.java @@ -17,77 +17,54 @@ package com.intellij.openapi.editor.impl.softwrap.mapping; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.ex.DocumentEx; -import com.intellij.openapi.editor.impl.AbstractEditorTest; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.impl.EditorStressTest; import com.intellij.openapi.editor.impl.SoftWrapModelImpl; import com.intellij.openapi.util.registry.Registry; -import gnu.trove.TIntObjectProcedure; import org.jetbrains.annotations.NotNull; import java.util.*; -public class SoftWrapStressTest extends AbstractEditorTest { - private static final int ITERATIONS = 10000; - private static final Long SEED_OVERRIDE = null; // set non-null value to run with a specific seed - - private static final List ourActions = Arrays.asList(new AddText("a"), - new AddText("\n"), - new AddText("\t"), - new RemoveCharacter(), - new MoveCharacter(), - new AddFoldRegion(), - new RemoveFoldRegion(), - new CollapseFoldRegion(), - new ExpandFoldRegion()); - - private final Random myRandom = new Random() {{ - //noinspection ConstantConditions - setSeed(mySeed = (SEED_OVERRIDE == null ? nextLong() : SEED_OVERRIDE)); - }}; - private long mySeed; - - public void testSoftWrapModelInternalCachesStayConsistentAfterDocumentAndFoldingChanges() { +public class SoftWrapStressTest extends EditorStressTest { + @Override + protected void setUp() throws Exception { + super.setUp(); Registry.get("editor.new.rendering").setValue(false); - int i = 0; + } + + @Override + protected void tearDown() throws Exception { try { - initText(""); - configureSoftWraps(10); - for (i = 1; i <= ITERATIONS; i++) { - doRandomAction(); - checkConsistency(); - } - } - catch (Throwable t) { - throw new RuntimeException("Failed when run with seed=" + mySeed + " in iteration " + i, t); - } - finally { Registry.get("editor.new.rendering").setValue(true); } + finally { + super.tearDown(); + } } - - private void doRandomAction() { - ourActions.get(myRandom.nextInt(ourActions.size())).perform(myEditor, myRandom); - } - - private static void checkConsistency() { - Set softWrapOffsets = checkSoftWraps(); - List cache = ((SoftWrapModelImpl)myEditor.getSoftWrapModel()).getDataMapper().getCache(); + + @Override + protected void checkConsistency(Editor editor) { + DocumentEx document = ((EditorEx)editor).getDocument(); + if (document.isInBulkUpdate()) return; + Set softWrapOffsets = checkSoftWraps(editor); + List cache = ((SoftWrapModelImpl)editor.getSoftWrapModel()).getDataMapper().getCache(); CacheEntry prevEntry = null; for (CacheEntry entry : cache) { boolean currentLineStartsWithSoftWrap = checkRelationBetweenNeighbourEntries(entry, prevEntry, softWrapOffsets); checkConsistencyWithinEntry(entry, currentLineStartsWithSoftWrap); - checkConsistencyWithFoldingsAndTabs(entry); + checkConsistencyWithFoldingsAndTabs(editor, entry); prevEntry = entry; } assertTrue(softWrapOffsets.isEmpty()); } - private static void checkConsistencyWithFoldingsAndTabs(CacheEntry entry) { - Map actualFoldRegions = new HashMap(); - List actualTabPositions = new ArrayList(); + private static void checkConsistencyWithFoldingsAndTabs(Editor editor, CacheEntry entry) { + Map actualFoldRegions = new HashMap<>(); + List actualTabPositions = new ArrayList<>(); for (int i = entry.startOffset; i < entry.endOffset; i++) { - FoldRegion region = myEditor.getFoldingModel().getCollapsedRegionAtOffset(i); + FoldRegion region = editor.getFoldingModel().getCollapsedRegionAtOffset(i); if (region == null) { - if (myEditor.getDocument().getCharsSequence().charAt(i) == '\t') { + if (editor.getDocument().getCharsSequence().charAt(i) == '\t') { actualTabPositions.add(i); } } @@ -97,16 +74,13 @@ public class SoftWrapStressTest extends AbstractEditorTest { } } } - final Map cachedFoldRegions = new HashMap(); - entry.getFoldingData().forEachEntry(new TIntObjectProcedure() { - @Override - public boolean execute(int offset, FoldingData data) { - cachedFoldRegions.put(offset, data.getFoldRegion()); - return true; - } + final Map cachedFoldRegions = new HashMap<>(); + entry.getFoldingData().forEachEntry((offset, data) -> { + cachedFoldRegions.put(offset, data.getFoldRegion()); + return true; }); assertEquals(actualFoldRegions, cachedFoldRegions); - List cachedTabPositions = new ArrayList(); + List cachedTabPositions = new ArrayList<>(); for (TabData tabData : entry.getTabData()) { cachedTabPositions.add(tabData.offset); } @@ -186,9 +160,9 @@ public class SoftWrapStressTest extends AbstractEditorTest { } @NotNull - private static Set checkSoftWraps() { - List softWraps = myEditor.getSoftWrapModel().getSoftWrapsForRange(0, myEditor.getDocument().getTextLength()); - Set softWrapOffsets = new HashSet(); + private static Set checkSoftWraps(Editor editor) { + List softWraps = editor.getSoftWrapModel().getSoftWrapsForRange(0, editor.getDocument().getTextLength()); + Set softWrapOffsets = new HashSet<>(); int lastOffset = -1; for (SoftWrap softWrap : softWraps) { assertEquals(softWrap.getStart(), softWrap.getEnd()); @@ -198,115 +172,4 @@ public class SoftWrapStressTest extends AbstractEditorTest { } return softWrapOffsets; } - - interface Action { - void perform(Editor editor, Random random); - } - - private static class AddText implements Action { - private final String myText; - - AddText(String text) { - myText = text; - } - - @Override - public void perform(Editor editor, Random random) { - Document document = editor.getDocument(); - int offset = random.nextInt(document.getTextLength() + 1); - document.insertString(offset, myText); - } - } - - private static class RemoveCharacter implements Action { - @Override - public void perform(Editor editor, Random random) { - Document document = editor.getDocument(); - int textLength = document.getTextLength(); - if (textLength <= 0) return; - int offset = random.nextInt(textLength); - document.deleteString(offset, offset + 1); - } - } - - private static class MoveCharacter implements Action { - @Override - public void perform(Editor editor, Random random) { - Document document = editor.getDocument(); - int textLength = document.getTextLength(); - if (textLength <= 0) return; - int offset = random.nextInt(textLength); - int targetOffset = random.nextInt(textLength + 1); - if (targetOffset < offset || targetOffset > offset + 1) { - ((DocumentEx)document).moveText(offset, offset + 1, targetOffset); - } - } - } - - private static class AddFoldRegion implements Action { - @Override - public void perform(final Editor editor, Random random) { - Document document = editor.getDocument(); - int textLength = document.getTextLength(); - if (textLength <= 0) return; - final int startOffset = random.nextInt(textLength + 1); - final int endOffset = random.nextInt(textLength + 1); - if (startOffset == endOffset) return; - final FoldingModel foldingModel = editor.getFoldingModel(); - foldingModel.runBatchFoldingOperation(new Runnable() { - @Override - public void run() { - foldingModel.addFoldRegion(Math.min(startOffset, endOffset), Math.max(startOffset, endOffset), "."); - } - }); - } - } - - private static class RemoveFoldRegion implements Action { - @Override - public void perform(final Editor editor, Random random) { - final FoldingModel foldingModel = editor.getFoldingModel(); - FoldRegion[] foldRegions = foldingModel.getAllFoldRegions(); - if (foldRegions.length == 0) return; - final FoldRegion region = foldRegions[random.nextInt(foldRegions.length)]; - foldingModel.runBatchFoldingOperation(new Runnable() { - @Override - public void run() { - foldingModel.removeFoldRegion(region); - } - }); - } - } - - private static class CollapseFoldRegion implements Action { - @Override - public void perform(final Editor editor, Random random) { - final FoldingModel foldingModel = editor.getFoldingModel(); - FoldRegion[] foldRegions = foldingModel.getAllFoldRegions(); - if (foldRegions.length == 0) return; - final FoldRegion region = foldRegions[random.nextInt(foldRegions.length)]; - foldingModel.runBatchFoldingOperation(new Runnable() { - @Override - public void run() { - region.setExpanded(false); - } - }); - } - } - - private static class ExpandFoldRegion implements Action { - @Override - public void perform(final Editor editor, Random random) { - final FoldingModel foldingModel = editor.getFoldingModel(); - FoldRegion[] foldRegions = foldingModel.getAllFoldRegions(); - if (foldRegions.length == 0) return; - final FoldRegion region = foldRegions[random.nextInt(foldRegions.length)]; - foldingModel.runBatchFoldingOperation(new Runnable() { - @Override - public void run() { - region.setExpanded(true); - } - }); - } - } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilTest.java index c90c85bd5b3d..0a39b739c208 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilTest.java @@ -113,6 +113,25 @@ public class VfsUtilTest extends PlatformTestCase { assertEquals("test text", content); } + public void testFindRelativeFile() throws Exception { + final VirtualFile root = VirtualFileManager.getInstance().findFileByUrl("temp:///"); + assertNotNull(root); + VirtualFile file = VfsUtilCore.findRelativeFile(root.getUrl(), null); + assertEquals(root, file); + + File ioTestDataDir = new File(PathManagerEx.getTestDataPath()); + VirtualFile testDataDir = LocalFileSystem.getInstance().findFileByIoFile(ioTestDataDir); + assertNotNull(testDataDir); + assertEquals(testDataDir, VfsUtilCore.findRelativeFile(VfsUtilCore.convertFromUrl(ioTestDataDir.toURI().toURL()), null)); + assertEquals(testDataDir, VfsUtilCore.findRelativeFile(ioTestDataDir.getAbsolutePath(), null)); + + File ioVfsDir = new File(ioTestDataDir, "vfs"); + VirtualFile vfsDir = LocalFileSystem.getInstance().findFileByIoFile(ioVfsDir); + assertNotNull(vfsDir); + assertEquals(vfsDir, VfsUtilCore.findRelativeFile(ioVfsDir.getAbsolutePath(), null)); + assertEquals(vfsDir, VfsUtilCore.findRelativeFile("vfs", testDataDir)); + } + public void testRelativePath() throws Exception { final File root = new File(PathManagerEx.getTestDataPath()); final File testRoot = new File(new File(root, "vfs"), "relativePath"); diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/ServersToolWindowManager.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/ServersToolWindowManager.java index 2b3c4f8baa06..d8c1064928b2 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/ServersToolWindowManager.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ui/ServersToolWindowManager.java @@ -64,33 +64,34 @@ public class ServersToolWindowManager extends AbstractProjectComponent { }); } - private void updateWindowAvailable(boolean showIfAvailable) { - boolean available = ServersToolWindowFactory.isAvailable(myProject); - + private void updateWindowAvailable(final boolean showIfAvailable) { final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject); - final ToolWindow toolWindow = toolWindowManager.getToolWindow(WINDOW_ID); - if (toolWindow == null) { - if (available) { - toolWindowManager.invokeLater(new Runnable() { + toolWindowManager.invokeLater(new Runnable() { - @Override - public void run() { + @Override + public void run() { + boolean available = ServersToolWindowFactory.isAvailable(myProject); + + final ToolWindow toolWindow = toolWindowManager.getToolWindow(WINDOW_ID); + + if (toolWindow == null) { + if (available) { createToolWindow(myProject, toolWindowManager).show(null); } - }); - } - return; - } + return; + } - boolean doShow = !toolWindow.isAvailable() && available; - if (toolWindow.isAvailable() && !available) { - toolWindow.hide(null); - } - toolWindow.setAvailable(available, null); - if (showIfAvailable && doShow) { - toolWindow.show(null); - } + boolean doShow = !toolWindow.isAvailable() && available; + if (toolWindow.isAvailable() && !available) { + toolWindow.hide(null); + } + toolWindow.setAvailable(available, null); + if (showIfAvailable && doShow) { + toolWindow.show(null); + } + } + }); } private static ToolWindow createToolWindow(Project project, ToolWindowManager toolWindowManager) { diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerUIActionsHandler.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerUIActionsHandler.java index 62ba4445b46a..9b79b8f5652b 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerUIActionsHandler.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerUIActionsHandler.java @@ -15,16 +15,10 @@ */ package com.intellij.execution.testframework.sm.runner.ui; -import com.intellij.execution.testframework.*; -import com.intellij.execution.testframework.actions.ScrollToTestSourceAction; -import com.intellij.execution.testframework.sm.SMRunnerUtil; +import com.intellij.execution.testframework.AbstractTestProxy; +import com.intellij.execution.testframework.TestConsoleProperties; import com.intellij.execution.testframework.sm.runner.ProxyFilters; import com.intellij.execution.testframework.sm.runner.SMTestProxy; -import com.intellij.openapi.application.ModalityState; -import com.intellij.pom.Navigatable; -import com.intellij.util.OpenSourceUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.List; @@ -67,20 +61,4 @@ public class SMTRunnerUIActionsHandler extends TestResultsViewer.SMEventsAdapter } } } - - public void onSelected(@Nullable final SMTestProxy selectedTestProxy, - @NotNull final TestResultsViewer viewer, - @NotNull final TestFrameworkRunningModel model) { - //TODO: tests o "onSelected" - SMRunnerUtil.runInEventDispatchThread(new Runnable() { - public void run() { - if (ScrollToTestSourceAction.isScrollEnabled(model)) { - final Navigatable descriptor = TestsUIUtil.getOpenFileDescriptor(selectedTestProxy, model); - if (descriptor != null) { - OpenSourceUtil.navigate(false, descriptor); - } - } - } - }, ModalityState.NON_MODAL); - } } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java index 4da5f6c16744..fe2f478346ca 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java @@ -20,6 +20,7 @@ import com.intellij.execution.TestStateStorage; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.testframework.*; +import com.intellij.execution.testframework.actions.ScrollToTestSourceAction; import com.intellij.execution.testframework.export.TestResultsXmlFormatter; import com.intellij.execution.testframework.sm.SMRunnerUtil; import com.intellij.execution.testframework.sm.TestHistoryConfiguration; @@ -47,8 +48,10 @@ import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.pom.Navigatable; import com.intellij.ui.JBColor; import com.intellij.util.Alarm; +import com.intellij.util.OpenSourceUtil; import com.intellij.util.PathUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.DateFormatUtil; @@ -197,6 +200,7 @@ public class SMTestRunnerResultsForm extends TestResultsPanel @Override public void pass(AbstractTestProxy testProxy) { if (testProxy == null) return; + final AbstractTestProxy selectedProxy = testProxy; //drill to the first leaf while (!testProxy.isLeaf()) { final List children = testProxy.getChildren(); @@ -213,6 +217,14 @@ public class SMTestRunnerResultsForm extends TestResultsPanel //pretend the selection on the first leaf //so if test would be run, tracking would be restarted myLastSelected = testProxy; + + //ensure scroll to source on explicit selection only + if (ScrollToTestSourceAction.isScrollEnabled(SMTestRunnerResultsForm.this)) { + final Navigatable descriptor = TestsUIUtil.getOpenFileDescriptor(selectedProxy, SMTestRunnerResultsForm.this); + if (descriptor != null) { + OpenSourceUtil.navigate(false, descriptor); + } + } } }); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/DocumentBasedReplaceHandler.java b/platform/structuralsearch/source/com/intellij/structuralsearch/DocumentBasedReplaceHandler.java index 1f319b8f15e5..ec0847d6c4f9 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/DocumentBasedReplaceHandler.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/DocumentBasedReplaceHandler.java @@ -45,7 +45,7 @@ public class DocumentBasedReplaceHandler extends StructuralReplaceHandler { PsiElement element = result.getMatch(); PsiFile file = element instanceof PsiFile ? (PsiFile)element : element.getContainingFile(); Document document = PsiDocumentManager.getInstance(myProject).getDocument(file); - TextRange textRange = result.getMatchRef().getElement().getTextRange(); + TextRange textRange = result.getMatch().getTextRange(); assert textRange != null; RangeMarker rangeMarker = document.createRangeMarker(textRange); rangeMarker.setGreedyToLeft(true); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/MatchResult.java b/platform/structuralsearch/source/com/intellij/structuralsearch/MatchResult.java index c5196e67178d..75ee67a63bfe 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/MatchResult.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/MatchResult.java @@ -10,8 +10,8 @@ import java.util.List; * Class describing the match result */ public abstract class MatchResult { - @NonNls public static final String LINE_MATCH = "line"; - @NonNls public static final String MULTI_LINE_MATCH = "context"; + @NonNls public static final String LINE_MATCH = "__line__"; + @NonNls public static final String MULTI_LINE_MATCH = "__multi_line__"; public abstract String getMatchImage(); @@ -26,4 +26,5 @@ public abstract class MatchResult { public abstract boolean hasSons(); public abstract boolean isScopeMatch(); public abstract boolean isMultipleMatch(); + public abstract boolean isTarget(); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java index ea25cdefb89a..41a1c264832f 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java @@ -221,7 +221,7 @@ public abstract class StructuralSearchProfile { if (info.getName().equals(match.getName())) { String replacementString = match.getMatchImage(); boolean forceAddingNewLine = false; - if (match.getAllSons().size() > 0 && !match.isScopeMatch()) { + if (match.hasSons() && !match.isScopeMatch()) { // compound matches StringBuilder buf = new StringBuilder(); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java index 50e64b6457b9..8d5309ad46b5 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/GlobalMatchingVisitor.java @@ -246,17 +246,15 @@ public class GlobalMatchingVisitor extends AbstractMatchingVisitor { matchContext.getSink().newMatch(result); } - private boolean doDispatch(final MatchResultImpl result, MatchResultImpl context) { + private boolean doDispatch(final MatchResult result, MatchResultImpl context) { boolean ret = false; - for (MatchResult _r : result.getAllSons()) { - final MatchResultImpl r = (MatchResultImpl)_r; - + for (MatchResult r : result.getAllSons()) { if ((r.isScopeMatch() && !r.isTarget()) || r.isMultipleMatch()) { ret |= doDispatch(r, context); } else if (r.isTarget()) { - r.setContext(context); + ((MatchResultImpl)r).setContext(context); matchContext.getSink().newMatch(r); ret = true; } @@ -273,19 +271,15 @@ public class GlobalMatchingVisitor extends AbstractMatchingVisitor { result.setMatchImage(match.getText()); } else { - MatchResultImpl sonresult; for (final PsiElement matchStatement : matchedNodes) { - result.getMatches().add( - sonresult = new MatchResultImpl( + result.getMatches().add(new MatchResultImpl( MatchResult.LINE_MATCH, matchStatement.getText(), new SmartPsiPointer(matchStatement), true ) ); - - sonresult.setParent(result); } result.setMatchRef( diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatchResultImpl.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatchResultImpl.java index 6278a6023382..58748a35b970 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatchResultImpl.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatchResultImpl.java @@ -3,7 +3,6 @@ package com.intellij.structuralsearch.impl.matcher; import com.intellij.psi.PsiElement; import com.intellij.structuralsearch.MatchResult; import com.intellij.structuralsearch.plugin.util.SmartPsiPointer; -import org.jetbrains.annotations.NonNls; import java.util.ArrayList; import java.util.Iterator; @@ -23,7 +22,6 @@ public final class MatchResultImpl extends MatchResult { private boolean myScopeMatch; private boolean myMultipleMatch; - @NonNls private static final String NULL = "null"; private MatchResultImpl myContext; MatchResultImpl() { @@ -42,21 +40,21 @@ public final class MatchResultImpl extends MatchResult { this.end = end; } + @Override public String getMatchImage() { - if (matchImage==null) { - matchImage = NULL; - } return matchImage; } - public void setParent(MatchResult parent) { - } - + @Override public SmartPsiPointer getMatchRef() { return matchRef; } + @Override public PsiElement getMatch() { + if (matchRef == null) { + return null; + } return matchRef.getElement(); } @@ -64,6 +62,7 @@ public final class MatchResultImpl extends MatchResult { matchRef = matchStart; } + @Override public String getName() { return name; } @@ -77,18 +76,22 @@ public final class MatchResultImpl extends MatchResult { return matches; } + @Override public List getAllSons() { return getMatches(); } + @Override public boolean hasSons() { - return matches!=null; + return matches!=null && matches.size() > 0; } + @Override public boolean isScopeMatch() { return myScopeMatch; } + @Override public boolean isMultipleMatch() { return myMultipleMatch; } @@ -159,6 +162,7 @@ public final class MatchResultImpl extends MatchResult { this.matchImage = matchImage; } + @Override public boolean isTarget() { return target; } @@ -171,6 +175,7 @@ public final class MatchResultImpl extends MatchResult { return matchImage==null; } + @Override public int getStart() { return start; } @@ -179,6 +184,7 @@ public final class MatchResultImpl extends MatchResult { this.start = start; } + @Override public int getEnd() { return end; } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java index b0ea748c8477..48eb7c471ae7 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java @@ -219,10 +219,6 @@ public class MatcherImpl { } } - Project getProject() { - return project; - } - /** * Finds the matches of given pattern starting from given tree element. * @throws MalformedPatternException diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java index 78744bad6390..afe40f03792c 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java @@ -437,7 +437,7 @@ public class PatternCompiler { addPredicate(handler, matchPredicate); } - addScriptConstraint(name, constraint, handler); + addScriptConstraint(project, name, constraint, handler); if (!StringUtil.isEmptyOrSpaces(constraint.getContainsConstraint())) { predicate = new ContainsPredicate(name, constraint.getContainsConstraint()); @@ -474,7 +474,7 @@ public class PatternCompiler { addPredicate(handler,predicate); } - addScriptConstraint(Configuration.CONTEXT_VAR_NAME, constraint, handler); + addScriptConstraint(project, Configuration.CONTEXT_VAR_NAME, constraint, handler); } buf.append(text.substring(prevOffset,text.length())); @@ -505,12 +505,12 @@ public class PatternCompiler { return elements; } - private static void addScriptConstraint(String name, MatchVariableConstraint constraint, SubstitutionHandler handler) { + private static void addScriptConstraint(Project project, String name, MatchVariableConstraint constraint, SubstitutionHandler handler) { if (constraint.getScriptCodeConstraint()!= null && constraint.getScriptCodeConstraint().length() > 2) { final String script = StringUtil.stripQuotesAroundValue(constraint.getScriptCodeConstraint()); final String s = ScriptSupport.checkValidScript(script); if (s != null) throw new MalformedPatternException("Script constraint for " + constraint.getName() + " has problem "+s); - MatchPredicate predicate = new ScriptPredicate(name, script); + MatchPredicate predicate = new ScriptPredicate(project, name, script); addPredicate(handler,predicate); } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SubstitutionHandler.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SubstitutionHandler.java index 2fb20927d329..1936818628df 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SubstitutionHandler.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SubstitutionHandler.java @@ -96,7 +96,7 @@ public class SubstitutionHandler extends MatchingHandler { if (match!=null) { if (start==0 && end==-1 && result.getStart()==0 && result.getEnd()==-1) { - matchresult = matchContext.getMatcher().match(match,result.getMatchRef().getElement()); + matchresult = matchContext.getMatcher().match(match,result.getMatch()); } else { matchresult = StructuralSearchUtil.getProfileByPsiElement(match).getText(match, start, end).equals( result.getMatchImage() @@ -167,7 +167,7 @@ public class SubstitutionHandler extends MatchingHandler { if (!substitution.isMultipleMatch()) { // adding intermediate node to contain all multiple matches - MatchResultImpl sonresult = new MatchResultImpl( + final MatchResultImpl sonresult = new MatchResultImpl( substitution.getName(), substitution.getMatchImage(), substitution.getMatchRef(), @@ -176,7 +176,6 @@ public class SubstitutionHandler extends MatchingHandler { target ); - sonresult.setParent(substitution); substitution.setMatchRef( new SmartPsiPointer(match == null ? null : match) ); @@ -193,7 +192,6 @@ public class SubstitutionHandler extends MatchingHandler { substitution.addSon( sonresult); } - result.setParent(substitution); substitution.addSon( result ); } } @@ -247,7 +245,7 @@ public class SubstitutionHandler extends MatchingHandler { if (minOccurs >= 1 && ( substitution == null || - StructuralSearchUtil.getProfileByFileType(context.getOptions().getFileType()).getElementContextByPsi(substitution.getMatchRef().getElement()) != elementContext + StructuralSearchUtil.getProfileByFileType(context.getOptions().getFileType()).getElementContextByPsi(substitution.getMatch()) != elementContext ) ) { return false; diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/ScriptLog.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/ScriptLog.java new file mode 100644 index 000000000000..340b5bb45dc4 --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/ScriptLog.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.structuralsearch.impl.matcher.predicates; + +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.project.Project; +import com.intellij.structuralsearch.SSRBundle; + +/** + * @author Bas Leijdekkers + */ +public class ScriptLog { + + private final NotificationGroup myEventLog; + private final Project myProject; + + public ScriptLog(Project project) { + myProject = project; + myEventLog = NotificationGroup.logOnlyGroup(SSRBundle.message("structural.search.title")); + } + + public void info(Object message) { + log(message, NotificationType.INFORMATION); + } + + public void warn(Object message) { + log(message, NotificationType.WARNING); + } + + public void error(Object message) { + log(message, NotificationType.ERROR); + } + + private void log(Object message, NotificationType type) { + final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); + String location = ""; + for (StackTraceElement e : stackTrace) { + final String methodName = e.getMethodName(); + if ("run".equals(methodName)) { + location = "(" + e.getFileName() + ":" + e.getLineNumber() + ") "; + break; + } + } + myEventLog.createNotification(location + String.valueOf(message), type).notify(myProject); + } +} diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/ScriptPredicate.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/ScriptPredicate.java index 9310eb9e70a0..c4c09167b99a 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/ScriptPredicate.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/ScriptPredicate.java @@ -1,5 +1,6 @@ package com.intellij.structuralsearch.impl.matcher.predicates; +import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.structuralsearch.impl.matcher.MatchContext; @@ -9,11 +10,12 @@ import com.intellij.structuralsearch.impl.matcher.MatchContext; public class ScriptPredicate extends AbstractStringBasedPredicate { private final ScriptSupport scriptSupport; - public ScriptPredicate(String name, String within) { + public ScriptPredicate(Project project, String name, String within) { super(name, within); - scriptSupport = new ScriptSupport(within, name); + scriptSupport = new ScriptSupport(project, within, name); } + @Override public boolean match(PsiElement node, PsiElement match, int start, int end, MatchContext context) { if (match == null) return false; diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/ScriptSupport.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/ScriptSupport.java index 60190275a902..f161dabd08d5 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/ScriptSupport.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/ScriptSupport.java @@ -1,11 +1,13 @@ package com.intellij.structuralsearch.impl.matcher.predicates; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.structuralsearch.MatchResult; import com.intellij.structuralsearch.SSRBundle; import com.intellij.structuralsearch.StructuralSearchException; import com.intellij.structuralsearch.StructuralSearchUtil; +import com.intellij.structuralsearch.plugin.ui.Configuration; import groovy.lang.Binding; import groovy.lang.GroovyRuntimeException; import groovy.lang.GroovyShell; @@ -32,12 +34,14 @@ import java.util.Map; */ public class ScriptSupport { private final Script script; + private final ScriptLog myScriptLog; - public ScriptSupport(String text, String name) { + public ScriptSupport(Project project, String text, String name) { + myScriptLog = new ScriptLog(project); File scriptFile = new File(text); GroovyShell shell = new GroovyShell(); try { - script = scriptFile.exists() ? shell.parse(scriptFile):shell.parse(text, name); + script = scriptFile.exists() ? shell.parse(scriptFile) : shell.parse(text, name); } catch (Exception ex) { Logger.getInstance(getClass().getName()).error(ex); throw new RuntimeException(ex); @@ -46,7 +50,7 @@ public class ScriptSupport { private static Map buildVariableMap(@NotNull MatchResult result, @NotNull Map out) { final String name = result.getName(); - if (name != null && !result.isMultipleMatch() && !result.isScopeMatch()) { + if (name != null && !result.isMultipleMatch()) { final Object value = out.get(name); final PsiElement match = StructuralSearchUtil.getPresentableElement(result.getMatch()); if (value == null) { @@ -78,6 +82,7 @@ public class ScriptSupport { public String evaluate(MatchResult result, PsiElement context) { try { final HashMap variableMap = new HashMap(); + variableMap.put("__log__", myScriptLog); if (result != null) { buildVariableMap(result, variableMap); if (context == null) { @@ -87,7 +92,7 @@ public class ScriptSupport { final Binding binding = new Binding(variableMap); context = StructuralSearchUtil.getPresentableElement(context); - binding.setVariable("__context__", context); + binding.setVariable(Configuration.CONTEXT_VAR_NAME, context); script.setBinding(binding); final Object o = script.run(); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/ReplacementBuilder.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/ReplacementBuilder.java index 2ec2c6ed3175..61c21f26180e 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/ReplacementBuilder.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/ReplacementBuilder.java @@ -34,8 +34,10 @@ public final class ReplacementBuilder { private final List parameterizations = new ArrayList(); private final Map replacementVarsMap; private final ReplaceOptions options; + private final Project myProject; ReplacementBuilder(final Project project,final ReplaceOptions options) { + myProject = project; replacementVarsMap = new HashMap(); this.options = options; String _replacement = options.getReplacement(); @@ -177,7 +179,7 @@ public final class ReplacementBuilder { if (scriptSupport == null) { String constraint = options.getVariableDefinition(info.getName()).getScriptCodeConstraint(); - scriptSupport = new ScriptSupport(StringUtil.stripQuotesAroundValue(constraint), info.getName()); + scriptSupport = new ScriptSupport(myProject, StringUtil.stripQuotesAroundValue(constraint), info.getName()); replacementVarsMap.put(info.getName(), scriptSupport); } return scriptSupport.evaluate(match, null); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/ReplacementContext.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/ReplacementContext.java index 07566796cf06..0bb427036f55 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/ReplacementContext.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/ReplacementContext.java @@ -42,7 +42,7 @@ public class ReplacementContext { if (variableMap != null) { for (String s : variableMap.keySet()) { final MatchResult matchResult = replacementInfo.getVariableMap().get(s); - PsiElement match = matchResult.getMatchRef() != null ? matchResult.getMatch() : null; + PsiElement match = matchResult.getMatch(); match = StructuralSearchUtil.getParentIfIdentifier(match); if (match instanceof PsiNamedElement) { diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java index 6ca23da13e7b..c0db4e7a24f7 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java @@ -390,7 +390,7 @@ public class Replacer { final MatchResult r = i.next(); if (MatchResult.LINE_MATCH.equals(r.getName())) { - PsiElement element = r.getMatchRef().getElement(); + PsiElement element = r.getMatch(); if (element instanceof PsiDocCommentBase) { // doc comment is not collapsed when created in block if (i.hasNext()) { @@ -409,7 +409,7 @@ public class Replacer { } } } else { - l.add( manager.createSmartPsiElementPointer(result.getMatchRef().getElement())); + l.add(manager.createSmartPsiElementPointer(result.getMatch())); } ReplacementInfoImpl replacementInfo = new ReplacementInfoImpl(); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java index ac3c39e4b9a2..71118f1e4030 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchCommand.java @@ -144,10 +144,10 @@ public class SearchCommand { if (MatchResult.MULTI_LINE_MATCH.equals(result.getName())) { int start = -1; int end = -1; - PsiElement parent = result.getMatchRef().getElement().getParent(); + PsiElement parent = result.getMatch().getParent(); for (final MatchResult matchResult : ((MatchResultImpl)result).getMatches()) { - PsiElement el = matchResult.getMatchRef().getElement(); + PsiElement el = matchResult.getMatch(); final int elementStart = el.getTextRange().getStartOffset(); if (start == -1 || start > elementStart) { diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 2aa293f3bba6..afba06233973 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -1174,6 +1174,36 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " Type.type.canonicalText\n" + // reference to '_Type ")\n\")]" + "static final '_Type 'variable = '_init;")); + + final String source2 = "class A {" + + " String s = new String();" + + " int m() {" + + " int i = 2+1;" + + " return i;" + + " }" + + "}"; + assertEquals("type of variables in script are as expected", 1, + findMatchesCount(source2, + "[script(\"" + + "import com.intellij.psi.*\n" + + "a instanceof PsiClass &&" + + "b instanceof PsiTypeElement &&" + + "c instanceof PsiField &&" + + "d instanceof PsiNewExpression &&" + + "e instanceof PsiTypeElement &&" + + "f instanceof PsiMethod &&" + + "g instanceof PsiTypeElement &&" + + "h instanceof PsiLocalVariable &&" + + "i instanceof PsiPolyadicExpression &&" + + "j instanceof PsiReferenceExpression" + + "\n\")]" + + "class '_a {" + + " '_b '_c = '_d;" + + " '_e '_f() {" + + " '_g '_h = '_i" + + " return '_j;" + + " }" + + "}")); } public void testCheckScriptValidation() { diff --git a/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java b/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java index f0df8f8b9ca9..c84fe76dcea3 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java @@ -30,6 +30,7 @@ import com.intellij.openapi.roots.ContentIterator; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; @@ -41,6 +42,7 @@ import com.intellij.util.indexing.IndexableFileSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.io.IOException; import static com.intellij.openapi.roots.ModuleRootModificationUtil.updateModel; @@ -70,7 +72,13 @@ public class LightProjectDescriptor { return ApplicationManager.getApplication().runWriteAction(new Computable() { @Override public Module compute() { - return ModuleManager.getInstance(project).newModule("light_idea_test_case.iml", getModuleType().getId()); + String moduleFilePath = "light_idea_test_case.iml"; + File imlFile = new File(moduleFilePath); + if (imlFile.exists()) { + //temporary workaround for IDEA-147530: otherwise if someone saved module with this name before the created module will get its settings + FileUtil.delete(imlFile); + } + return ModuleManager.getInstance(project).newModule(moduleFilePath, getModuleType().getId()); } }); } diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 0cbe7c600eee..3d5a24c1f03f 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -127,6 +127,8 @@ public abstract class UsefulTestCase extends TestCase { } } + private boolean oldDisposerDebug; + protected boolean shouldContainTempFiles() { return true; } @@ -142,11 +144,15 @@ public abstract class UsefulTestCase extends TestCase { myTempDir = new File(ORIGINAL_TEMP_DIR, TEMP_DIR_MARKER + testName).getPath(); FileUtil.resetCanonicalTempPathCache(myTempDir); } - ApplicationInfoImpl.setInPerformanceTest(isPerformanceTest()); + boolean isPerformanceTest = isPerformanceTest(); + ApplicationInfoImpl.setInPerformanceTest(isPerformanceTest); + // turn off Disposer debugging for performance tests + oldDisposerDebug = Disposer.setDebugMode(Disposer.isDebugMode() && !isPerformanceTest); } @Override protected void tearDown() throws Exception { + Disposer.setDebugMode(oldDisposerDebug); try { Disposer.dispose(myTestRootDisposable); cleanupSwingDataStructures(); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/BareTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/BareTestFixture.java index 5c944017eccc..04c6fa4bda7d 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/BareTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/BareTestFixture.java @@ -15,7 +15,11 @@ */ package com.intellij.testFramework.fixtures; +import com.intellij.openapi.Disposable; + /** * A fixture which provides only {@link com.intellij.openapi.application.Application application} and app-level components. */ -public interface BareTestFixture extends IdeaTestFixture { } \ No newline at end of file +public interface BareTestFixture extends IdeaTestFixture { + Disposable getTestRootDisposable(); +} \ No newline at end of file diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/BareTestFixtureTestCase.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/BareTestFixtureTestCase.java index aa43d7db999d..25212b12b2d8 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/BareTestFixtureTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/BareTestFixtureTestCase.java @@ -15,6 +15,7 @@ */ package com.intellij.testFramework.fixtures; +import com.intellij.openapi.Disposable; import com.intellij.testFramework.PlatformTestUtil; import org.jetbrains.annotations.NotNull; import org.junit.After; @@ -43,4 +44,9 @@ public abstract class BareTestFixtureTestCase { protected final String getTestName(boolean lowercaseFirstLetter) { return PlatformTestUtil.getTestName(myNameRule.getMethodName(), lowercaseFirstLetter); } + + @NotNull + public final Disposable getTestRootDisposable() { + return myFixture.getTestRootDisposable(); + } } \ No newline at end of file diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index dd52c9fc66e4..f32e275c7337 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -1893,10 +1893,10 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig Assert.assertNotNull(strings); final List actual = strings.subList(0, Math.min(expected.length, strings.size())); if (!actual.equals(Arrays.asList(expected))) { - UsefulTestCase.assertOrderedEquals(DumpLookupElementWeights.getLookupElementWeights(lookup), expected); + UsefulTestCase.assertOrderedEquals(DumpLookupElementWeights.getLookupElementWeights(lookup, false), expected); } if (selected != list.getSelectedIndex()) { - System.out.println(DumpLookupElementWeights.getLookupElementWeights(lookup)); + System.out.println(DumpLookupElementWeights.getLookupElementWeights(lookup, false)); } Assert.assertEquals(selected, list.getSelectedIndex()); } diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/ScrollToTestSourceAction.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/ScrollToTestSourceAction.java index dd2a417a5a2f..3254e58a98c0 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/actions/ScrollToTestSourceAction.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/ScrollToTestSourceAction.java @@ -32,7 +32,7 @@ public class ScrollToTestSourceAction extends ToggleBooleanProperty.Disablable { protected boolean isEnabled() { final AbstractProperty.AbstractPropertyContainer properties = getProperties(); final TestFrameworkRunningModel model = myModel; - return isEnabled(properties, model); + return isEnabled(model); } @Override @@ -40,14 +40,13 @@ public class ScrollToTestSourceAction extends ToggleBooleanProperty.Disablable { return true; } - private static boolean isEnabled(final AbstractProperty.AbstractPropertyContainer properties, final TestFrameworkRunningModel model) { - if (!TestConsoleProperties.TRACK_RUNNING_TEST.value(properties)) return true; + private static boolean isEnabled(final TestFrameworkRunningModel model) { return model != null && !model.isRunning(); } public static boolean isScrollEnabled(final TestFrameworkRunningModel model) { final TestConsoleProperties properties = model.getProperties(); - return isEnabled(properties, model) && TestConsoleProperties.SCROLL_TO_SOURCE.value(properties); + return isEnabled(model) && TestConsoleProperties.SCROLL_TO_SOURCE.value(properties); } public void setModel(final TestFrameworkRunningModel model) { diff --git a/platform/util/src/com/intellij/openapi/util/Disposer.java b/platform/util/src/com/intellij/openapi/util/Disposer.java index 6307017967ac..5d9b94244bf6 100644 --- a/platform/util/src/com/intellij/openapi/util/Disposer.java +++ b/platform/util/src/com/intellij/openapi/util/Disposer.java @@ -23,6 +23,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -126,12 +127,18 @@ public class Disposer { } } + @TestOnly public static boolean isEmpty() { return ourDebugMode && ourTree.isEmpty(); } - public static void setDebugMode(final boolean debugMode) { + /** + * @return old value + */ + public static boolean setDebugMode(final boolean debugMode) { + boolean oldValue = ourDebugMode; ourDebugMode = debugMode; + return oldValue; } public static boolean isDebugMode() { diff --git a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java index 5ce40516f200..4f356c6d8801 100644 --- a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java +++ b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package com.intellij.openapi.util.objectTree; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.util.Disposer; import com.intellij.util.SmartList; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -46,13 +47,12 @@ final class ObjectNode { ObjectNode(@NotNull ObjectTree tree, @Nullable ObjectNode parentNode, @NotNull T object, - long modification, - @Nullable final Throwable trace) { + long modification) { myTree = tree; myParent = parentNode; myObject = object; - myTrace = trace; + myTrace = Disposer.isDebugMode() ? new Throwable() : null; myOwnModification = modification; } @@ -171,7 +171,7 @@ final class ObjectNode { @Override @NonNls public String toString() { - return "Node: " + myObject.toString(); + return "Node: " + myObject; } Throwable getTrace() { diff --git a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java index 11212543a1d2..6340aafb237a 100644 --- a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java +++ b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,9 @@ package com.intellij.openapi.util.objectTree; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Disposer; import com.intellij.util.ArrayUtil; +import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; -import gnu.trove.Equality; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -59,11 +58,12 @@ public final class ObjectTree { public final void register(@NotNull T parent, @NotNull T child) { synchronized (treeLock) { - ObjectNode parentNode = getOrCreateNodeFor(parent, null); + ObjectNode parentNode = getNode(parent); + if (parentNode == null) parentNode = createNodeFor(parent, null); ObjectNode childNode = getNode(child); if (childNode == null) { - childNode = createNodeFor(child, parentNode, Disposer.isDebugMode() ? new Throwable() : null); + childNode = createNodeFor(child, parentNode); } else { ObjectNode oldParent = childNode.getParent(); @@ -72,38 +72,26 @@ public final class ObjectTree { } } myRootObjects.remove(child); - checkWasNotAddedAlready(childNode, child); + + checkWasNotAddedAlready(parentNode, childNode); + parentNode.addChild(childNode); fireRegistered(childNode.getObject()); } } - private void checkWasNotAddedAlready(@NotNull ObjectNode childNode, @NotNull T child) { - ObjectNode parent = childNode.getParent(); - boolean childIsInTree = parent != null; - if (!childIsInTree) return; - - while (parent != null) { - if (parent.getObject() == child) { - LOG.error(child + " was already added as a child of: " + parent); + private void checkWasNotAddedAlready(ObjectNode childNode, @NotNull ObjectNode parentNode) { + for (ObjectNode node = childNode; node != null; node = node.getParent()) { + if (node == parentNode) { + throw new IncorrectOperationException("'"+childNode.getObject() + "' was already added as a child of '" + parentNode.getObject()+"'"); } - parent = parent.getParent(); } } @NotNull - private ObjectNode getOrCreateNodeFor(@NotNull T object, @Nullable ObjectNode defaultParent) { - final ObjectNode node = getNode(object); - - if (node != null) return node; - - return createNodeFor(object, defaultParent, Disposer.isDebugMode() ? new Throwable() : null); - } - - @NotNull - private ObjectNode createNodeFor(@NotNull T object, @Nullable ObjectNode parentNode, @Nullable final Throwable trace) { - final ObjectNode newNode = new ObjectNode(this, parentNode, object, getNextModification(), trace); + private ObjectNode createNodeFor(@NotNull T object, @Nullable ObjectNode parentNode) { + final ObjectNode newNode = new ObjectNode(this, parentNode, object, getNextModification()); if (parentNode == null) { myRootObjects.add(object); } @@ -125,9 +113,7 @@ public final class ObjectTree { executeUnregistered(object, action); return true; } - else { - return false; - } + return false; } node.execute(disposeTree, action); return true; @@ -138,7 +124,7 @@ public final class ObjectTree { @NotNull List recursiveGuard, @NotNull final ObjectTreeAction action) { synchronized (recursiveGuard) { - if (ArrayUtil.indexOf(recursiveGuard, object, Equality.IDENTITY) != -1) return; + if (ArrayUtil.indexOf(recursiveGuard, object, ContainerUtil.identityStrategy()) != -1) return; recursiveGuard.add(object); } @@ -147,7 +133,7 @@ public final class ObjectTree { } finally { synchronized (recursiveGuard) { - int i = ArrayUtil.lastIndexOf(recursiveGuard, object, Equality.IDENTITY); + int i = ArrayUtil.lastIndexOf(recursiveGuard, object, ContainerUtil.identityStrategy()); assert i != -1; recursiveGuard.remove(i); } @@ -216,7 +202,7 @@ public final class ObjectTree { } } } - + @TestOnly public boolean isEmpty() { synchronized (treeLock) { diff --git a/platform/util/src/com/intellij/ui/components/JBPanel.java b/platform/util/src/com/intellij/ui/components/JBPanel.java index b265c961e496..fb0101033965 100644 --- a/platform/util/src/com/intellij/ui/components/JBPanel.java +++ b/platform/util/src/com/intellij/ui/components/JBPanel.java @@ -16,6 +16,7 @@ package com.intellij.ui.components; import com.intellij.util.ui.JBFont; +import com.intellij.util.ui.JBUI; import com.intellij.util.ui.components.JBComponent; import javax.swing.*; @@ -27,6 +28,12 @@ import java.awt.*; */ @SuppressWarnings("unchecked") public class JBPanel extends JPanel implements JBComponent { + private Integer myPreferredWidth; + private Integer myPreferredHeight; + private Integer myMaximumWidth; + private Integer myMaximumHeight; + private Integer myMinimumWidth; + private Integer myMinimumHeight; public JBPanel(LayoutManager layout, boolean isDoubleBuffered) { super(layout, isDoubleBuffered); @@ -67,4 +74,57 @@ public class JBPanel extends JPanel implements JBComponent setOpaque(true); return (T)this; } + + public T withPreferredWidth(int width) { + myPreferredWidth = width; + return (T)this; + } + + public T withPreferredHeight(int height) { + myPreferredHeight = height; + return (T)this; + } + + public T withMaximumWidth(int width) { + myMaximumWidth = width; + return (T)this; + } + + public T withMaximumHeight(int height) { + myMaximumHeight = height; + return (T)this; + } + + public T withMinimumWidth(int width) { + myMinimumWidth = width; + return (T)this; + } + + public T withMinimumHeight(int height) { + myMinimumHeight = height; + return (T)this; + } + + @Override + public Dimension getPreferredSize() { + return getSize(super.getPreferredSize(), myPreferredWidth, myPreferredHeight, isPreferredSizeSet()); + } + + @Override + public Dimension getMaximumSize() { + return getSize(super.getMaximumSize(), myMaximumWidth, myMaximumHeight, isMaximumSizeSet()); + } + + @Override + public Dimension getMinimumSize() { + return getSize(super.getMinimumSize(), myMinimumWidth, myMinimumHeight, isMinimumSizeSet()); + } + + private static Dimension getSize(Dimension size, Integer width, Integer height, boolean isSet) { + if (!isSet && size != null) { + if (width != null) size.width = JBUI.scale(width); + if (height != null) size.height = JBUI.scale(height); + } + return size; + } } diff --git a/platform/util/src/com/intellij/util/io/SafeFileOutputStream.java b/platform/util/src/com/intellij/util/io/SafeFileOutputStream.java index 6596b54a0982..481022132e0f 100644 --- a/platform/util/src/com/intellij/util/io/SafeFileOutputStream.java +++ b/platform/util/src/com/intellij/util/io/SafeFileOutputStream.java @@ -45,11 +45,11 @@ public class SafeFileOutputStream extends OutputStream { myTargetFile = target; myPreserveAttributes = preserveAttributes; myBackupFile = new File(myTargetFile.getParentFile(), myTargetFile.getName() + EXTENSION_BAK); - //noinspection IOResourceOpenedButNotSafelyClosed myBackupStream = new FileOutputStream(myBackupFile); } @Override + @SuppressWarnings("Duplicates") public void write(byte[] b) throws IOException { try { myBackupStream.write(b); @@ -62,6 +62,7 @@ public class SafeFileOutputStream extends OutputStream { } @Override + @SuppressWarnings("Duplicates") public void write(int b) throws IOException { try { myBackupStream.write(b); @@ -74,6 +75,7 @@ public class SafeFileOutputStream extends OutputStream { } @Override + @SuppressWarnings("Duplicates") public void write(byte[] b, int off, int len) throws IOException { try { myBackupStream.write(b, off, len); @@ -137,4 +139,4 @@ public class SafeFileOutputStream extends OutputStream { throw new IOException(CommonBundle.message("safe.write.drop.temp", oldFile)); } } -} +} \ No newline at end of file diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/IoTestUtil.java b/platform/util/testSrc/com/intellij/openapi/util/io/IoTestUtil.java index 1e6e6deb03c8..ebc96ce401fd 100644 --- a/platform/util/testSrc/com/intellij/openapi/util/io/IoTestUtil.java +++ b/platform/util/testSrc/com/intellij/openapi/util/io/IoTestUtil.java @@ -208,7 +208,7 @@ public class IoTestUtil { private static int runCommand(final ProcessBuilder command) throws IOException, InterruptedException { command.redirectErrorStream(true); final Process process = command.start(); - new Thread(new Runnable() { + Thread thread = new Thread(new Runnable() { @Override public void run() { try { @@ -228,8 +228,11 @@ public class IoTestUtil { throw new RuntimeException(e); } } - },"io test").start(); - return process.waitFor(); + }, "io test"); + thread.start(); + int ret = process.waitFor(); + thread.join(); + return ret; } public static void assertTimestampsEqual(final long expected, final long actual) { diff --git a/platform/util/testSrc/com/intellij/openapi/util/objectTree/DisposerTest.java b/platform/util/testSrc/com/intellij/openapi/util/objectTree/DisposerTest.java index ce4132496aea..84aeea82e008 100644 --- a/platform/util/testSrc/com/intellij/openapi/util/objectTree/DisposerTest.java +++ b/platform/util/testSrc/com/intellij/openapi/util/objectTree/DisposerTest.java @@ -17,6 +17,7 @@ package com.intellij.openapi.util.objectTree; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.Disposer; +import com.intellij.util.IncorrectOperationException; import junit.framework.TestCase; import org.jetbrains.annotations.NonNls; @@ -216,11 +217,10 @@ public class DisposerTest extends TestCase { } private class MyDisposable implements Disposable { - - private boolean myDisposed = false; + private boolean myDisposed; protected String myName; - public MyDisposable(@NonNls String aName) { + MyDisposable(@NonNls String aName) { myName = aName; } @@ -252,7 +252,7 @@ public class DisposerTest extends TestCase { } private class SelDisposable extends MyDisposable { - public SelDisposable(@NonNls String aName) { + private SelDisposable(@NonNls String aName) { super(aName); } @@ -276,4 +276,40 @@ public class DisposerTest extends TestCase { return result.toString(); } + + public void testIncest() { + Disposable parent = newDisposable("parent"); + Disposable child = newDisposable("child"); + Disposer.register(parent, child); + + Disposable grand = newDisposable("grand"); + Disposer.register(child, grand); + + try { + Disposer.register(grand, parent); + fail("must not allow"); + } + catch (IncorrectOperationException e) { + assertEquals("'grand' was already added as a child of 'parent'", e.getMessage()); + } + finally { + Disposer.dispose(grand); + Disposer.dispose(child); + Disposer.dispose(parent); + } + } + + private static Disposable newDisposable(final String name) { + return new Disposable() { + @Override + public void dispose() { + + } + + @Override + public String toString() { + return name; + } + }; + } } diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/LocalChangesUnderRootsTest.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/LocalChangesUnderRootsTest.java index 1ad2f8453f71..14d1d817b737 100644 --- a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/LocalChangesUnderRootsTest.java +++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/LocalChangesUnderRootsTest.java @@ -1,11 +1,26 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.openapi.vcs; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.ChangeListManagerImpl; import com.intellij.openapi.vcs.changes.ContentRevision; import com.intellij.openapi.vcs.changes.committed.MockAbstractVcs; -import com.intellij.testFramework.vcs.MockContentRevision; import com.intellij.openapi.vcs.changes.ui.ChangesComparator; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.impl.LocalChangesUnderRoots; @@ -15,9 +30,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.VfsTestUtil; import com.intellij.testFramework.vcs.MockChangeListManager; +import com.intellij.testFramework.vcs.MockContentRevision; import com.intellij.vcsUtil.VcsUtil; -import org.junit.Before; -import org.junit.Test; import java.lang.reflect.Field; import java.util.*; @@ -31,7 +45,7 @@ public class LocalChangesUnderRootsTest extends PlatformTestCase { private MockChangeListManager myChangeListManager; private VirtualFile myBaseDir; - @Before + @Override protected void setUp() throws Exception { super.setUp(); @@ -43,6 +57,12 @@ public class LocalChangesUnderRootsTest extends PlatformTestCase { substituteChangeListManager(); } + @Override + protected void tearDown() throws Exception { + ((ChangeListManagerImpl) ChangeListManager.getInstance(myProject)).stopEveryThingIfInTestMode(); + super.tearDown(); + } + // This is not good, but declaring MockChangeListManager might break other tests private void substituteChangeListManager() throws NoSuchFieldException, IllegalAccessException { Field myChangeManager = LocalChangesUnderRoots.class.getDeclaredField("myChangeManager"); @@ -50,7 +70,6 @@ public class LocalChangesUnderRootsTest extends PlatformTestCase { myChangeManager.set(myLocalChangesUnderRoots, myChangeListManager); } - @Test public void testChangesInTwoGitRoots() { AllVcsesI myVcses = AllVcses.getInstance(myProject); myVcses.registerManually(new MockAbstractVcs(myProject, "Mock")); @@ -67,7 +86,7 @@ public class LocalChangesUnderRootsTest extends PlatformTestCase { Map> expected = new HashMap>(); expected.put(roots.get(0), Arrays.asList(changeBeforeCommunity, changeAfterCommunity)); - expected.put(roots.get(1), Arrays.asList(changeInCommunity)); + expected.put(roots.get(1), Collections.singletonList(changeInCommunity)); Map> changesUnderRoots = myLocalChangesUnderRoots.getChangesUnderRoots(roots); assertEqualMaps(expected, changesUnderRoots); diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/collapsing/DottedFilterEdgesGenerator.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/collapsing/DottedFilterEdgesGenerator.java index cc5f42f6af70..6f31ad03fe02 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/collapsing/DottedFilterEdgesGenerator.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/collapsing/DottedFilterEdgesGenerator.java @@ -67,9 +67,16 @@ public class DottedFilterEdgesGenerator { // update specified range private void update() { downWalk(); + cleanup(); upWalk(); } + private void cleanup() { + for (int currentNodeIndex = myUpIndex; currentNodeIndex <= myDownIndex; currentNodeIndex++) { + myNumbers.setNumber(currentNodeIndex, Integer.MAX_VALUE); + } + } + private boolean hasDottedEdges(int nodeIndex, boolean isUp) { for (GraphEdge edge : myModification.getEdgesToAdd().getAdjacentEdges(nodeIndex, EdgeFilter.NORMAL_ALL)) { if (edge.getType() == DOTTED) { diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/BekBaseController.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/BekBaseController.java index 573d1f7dffc9..0e941ce5a183 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/BekBaseController.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/BekBaseController.java @@ -25,6 +25,7 @@ import com.intellij.vcs.log.graph.api.elements.GraphNodeType; import com.intellij.vcs.log.graph.api.permanent.PermanentGraphInfo; import com.intellij.vcs.log.graph.impl.facade.bek.BekChecker; import com.intellij.vcs.log.graph.impl.facade.bek.BekIntMap; +import com.intellij.vcs.log.graph.impl.permanent.PermanentLinearGraphImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,9 +40,9 @@ public class BekBaseController extends CascadeController { public BekBaseController(@NotNull PermanentGraphInfo permanentGraphInfo, @NotNull BekIntMap bekIntMap) { super(null, permanentGraphInfo); myBekIntMap = bekIntMap; - myBekGraph = new BekLinearGraph(); + myBekGraph = new BekLinearGraph(myBekIntMap, myPermanentGraphInfo.getPermanentLinearGraph()); - assert BekChecker.checkLinearGraph(myBekGraph); // todo drop later + BekChecker.checkLinearGraph(myBekGraph); } @NotNull @@ -85,16 +86,18 @@ public class BekBaseController extends CascadeController { return myBekGraph; } - private class BekLinearGraph implements LinearGraph { - @NotNull private final LinearGraph myPermanentGraph; + public static class BekLinearGraph implements LinearGraph { + @NotNull private final LinearGraph myLinearGraph; + @NotNull private final BekIntMap myBekIntMap; - private BekLinearGraph() { - myPermanentGraph = myPermanentGraphInfo.getPermanentLinearGraph(); + public BekLinearGraph(@NotNull BekIntMap bekIntMap, @NotNull LinearGraph linearGraph) { + myLinearGraph = linearGraph; + myBekIntMap = bekIntMap; } @Override public int nodesCount() { - return myPermanentGraph.nodesCount(); + return myLinearGraph.nodesCount(); } @Nullable @@ -107,7 +110,7 @@ public class BekBaseController extends CascadeController { @NotNull @Override public List getAdjacentEdges(int nodeIndex, @NotNull EdgeFilter filter) { - return map(myPermanentGraph.getAdjacentEdges(myBekIntMap.getUsualIndex(nodeIndex), filter), new Function() { + return map(myLinearGraph.getAdjacentEdges(myBekIntMap.getUsualIndex(nodeIndex), filter), new Function() { @Override public GraphEdge fun(GraphEdge edge) { return new GraphEdge(getNodeIndex(edge.getUpNodeIndex()), getNodeIndex(edge.getDownNodeIndex()), edge.getTargetId(), diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/bek/BekBranchCreator.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/bek/BekBranchCreator.java index f8092d6b503f..df2d13e14c0c 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/bek/BekBranchCreator.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/bek/BekBranchCreator.java @@ -79,7 +79,7 @@ class BekBranchCreator { // almost ok node, except (may be) up nodes boolean hasUndoneUpNodes = false; for (int upNode : getUpNodes(myPermanentGraph, downNode)) { - if (!myDoneNodes.get(upNode) && myGraphLayout.getLayoutIndex(upNode) <= currentLayout) { + if (!myDoneNodes.get(upNode) && myGraphLayout.getLayoutIndex(upNode) <= myGraphLayout.getLayoutIndex(downNode)) { hasUndoneUpNodes = true; break; } diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/bek/BekChecker.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/bek/BekChecker.java index b1dcc6a9bdd9..6e6cd7e0316a 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/bek/BekChecker.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/bek/BekChecker.java @@ -16,8 +16,10 @@ package com.intellij.vcs.log.graph.impl.facade.bek; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Pair; import com.intellij.vcs.log.graph.api.LinearGraph; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import static com.intellij.vcs.log.graph.utils.LinearGraphUtils.getDownNodes; import static com.intellij.vcs.log.graph.utils.LinearGraphUtils.getUpNodes; @@ -25,17 +27,29 @@ import static com.intellij.vcs.log.graph.utils.LinearGraphUtils.getUpNodes; public class BekChecker { private final static Logger LOG = Logger.getInstance("#com.intellij.vcs.log.graph.impl.facade.bek.BekChecker"); - public static boolean checkLinearGraph(@NotNull LinearGraph linearGraph) { + public static void checkLinearGraph(@NotNull LinearGraph linearGraph) { + Pair reversedEdge = findReversedEdge(linearGraph); + if (reversedEdge != null) { + LOG.error("Illegal edge: up node " + reversedEdge.first + ", downNode " + reversedEdge.second); + } + } + + @Nullable + public static Pair findReversedEdge(@NotNull LinearGraph linearGraph) { for (int i = 0; i < linearGraph.nodesCount(); i++) { for (int downNode : getDownNodes(linearGraph, i)) { - if (downNode <= i) LOG.error("Illegal node: " + i + ", with downNode: " + downNode); + if (downNode <= i) { + return Pair.create(i, downNode); + } } for (int upNode : getUpNodes(linearGraph, i)) { - if (upNode >= i) LOG.error("Illegal node: " + i + ", with upNode: " + upNode); + if (upNode >= i) { + return Pair.create(upNode, i); + } } } - return true; + return null; } } diff --git a/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/TestGraphBuilder.kt b/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/TestGraphBuilder.kt index b55f3c721e57..1e35ca5d9ff0 100644 --- a/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/TestGraphBuilder.kt +++ b/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/TestGraphBuilder.kt @@ -59,8 +59,8 @@ public class TestGraphBuilder : BaseTestGraphBuilder { public fun done(): LinearGraph = TestLinearGraph(nodes) - public fun Int.invoke(): Unit = newNode(asSimpleNode()) - public fun Int.invoke(vararg edge: Int): Unit = newNode(asSimpleNode(), edge.asSimpleEdges()) + public operator fun Int.invoke(): Unit = newNode(asSimpleNode()) + public operator fun Int.invoke(vararg edge: Int): Unit = newNode(asSimpleNode(), edge.asSimpleEdges()) public fun Int.invoke(vararg edge: SimpleEdge): Unit = newNode(asSimpleNode(), edge.toList()) public fun SimpleNode.invoke(): Unit = newNode(this) public fun SimpleNode.invoke(vararg edge: Int): Unit = newNode(this, edge.asSimpleEdges()) diff --git a/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/linearBek/BekTest.kt b/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/linearBek/BekTest.kt new file mode 100644 index 000000000000..55568458dcf3 --- /dev/null +++ b/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/linearBek/BekTest.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.vcs.log.graph.linearBek + +import com.intellij.vcs.log.graph.TestGraphBuilder +import org.junit.Test + +class BekTest { + fun runTest(beforeBekBuilder: TestGraphBuilder.() -> Unit, afterBekBuilder: TestGraphBuilder.() -> Unit) { + assertEquals(afterBekBuilder, runBek(beforeBekBuilder)) + } + + @Test fun ea68497() = runTest({ + 0(1, 3) + 1(4, 2) + 2(4, 3) + 3() + 4() + }, { + 0(1, 3) + 1(4, 2) + 2(4, 3) + 3() + 4() + }) + + @Test fun simpleMerge() = runTest({ + 0(1, 2) + 1(3) + 2(4) + 3(5) + 4(5) + 5() + }, { + 0(1, 2) + 2(4) + 4(5) + 1(3) + 3(5) + 5() + }) + + @Test fun twoHeads() = runTest({ + 0(2) + 1(2) + 2() + }, { + 1(2) + 0(2) + 2() + }) + + @Test fun simpleMergeWithTwoHeads() = runTest({ + 0(2, 3) + 1(4) + 2(4) + 3(5) + 4(6) + 5(6) + 6() + }, { + 1(4) + 0(2, 3) + 3(5) + 5(6) + 2(4) + 4(6) + 6() + }) +} + diff --git a/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/linearBek/TestUtils.kt b/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/linearBek/TestUtils.kt index d9941724beb0..2ae82a4024f1 100644 --- a/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/linearBek/TestUtils.kt +++ b/platform/vcs-log/graph/test/com/intellij/vcs/log/graph/linearBek/TestUtils.kt @@ -15,14 +15,18 @@ */ package com.intellij.vcs.log.graph.linearBek -import com.intellij.vcs.log.graph.utils.TimestampGetter import com.intellij.vcs.log.graph.TestGraphBuilder -import com.intellij.vcs.log.graph.impl.permanent.GraphLayoutBuilder import com.intellij.vcs.log.graph.api.LinearGraph -import com.intellij.vcs.log.graph.graph -import org.junit.Assert.assertEquals import com.intellij.vcs.log.graph.asTestGraphString +import com.intellij.vcs.log.graph.graph +import com.intellij.vcs.log.graph.impl.facade.BekBaseController +import com.intellij.vcs.log.graph.impl.facade.bek.BekChecker +import com.intellij.vcs.log.graph.impl.facade.bek.BekSorter +import com.intellij.vcs.log.graph.impl.permanent.GraphLayoutBuilder import com.intellij.vcs.log.graph.impl.permanent.GraphLayoutImpl +import com.intellij.vcs.log.graph.utils.TimestampGetter +import org.junit.Assert.assertEquals +import kotlin.test.assertNull public class DummyTimestampGetter(val nodesCount: Int) : TimestampGetter { override fun size(): Int { @@ -35,7 +39,22 @@ public class DummyTimestampGetter(val nodesCount: Int) : TimestampGetter { } public fun buildLayout(graphBuilder: TestGraphBuilder.() -> Unit): GraphLayoutImpl { - return GraphLayoutBuilder.build(graph(graphBuilder), {nodeIndex1, nodeIndex2 -> nodeIndex1 - nodeIndex2 }) + return GraphLayoutBuilder.build(graph(graphBuilder), { nodeIndex1, nodeIndex2 -> nodeIndex1 - nodeIndex2 }) +} + +fun runBek(graphBuilder: TestGraphBuilder.() -> Unit): BekBaseController.BekLinearGraph { + val beforeBek = graph(graphBuilder) + val beforeLayout = buildLayout(graphBuilder) + + val bekMap = BekSorter.createBekMap(beforeBek, beforeLayout, DummyTimestampGetter(beforeBek.nodesCount())) + val afterBek = BekBaseController.BekLinearGraph(bekMap, beforeBek) + + val edge = BekChecker.findReversedEdge(afterBek) + if (edge != null) { + assertNull(Pair(bekMap.getUsualIndex(edge.first), bekMap.getUsualIndex(edge.second)), "Found reversed edge"); + } + + return afterBek } public fun runLinearBek(graphBuilder: TestGraphBuilder.() -> Unit): LinearBekGraph { @@ -49,4 +68,4 @@ public fun runLinearBek(graphBuilder: TestGraphBuilder.() -> Unit): LinearBekGra public fun assertEquals(expected: TestGraphBuilder.() -> Unit, actual: LinearGraph): Unit { assertEquals(graph(expected).asTestGraphString(), actual.asTestGraphString()) -} \ No newline at end of file +} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java index 9afff78ef6e5..65f0aeadde50 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java @@ -16,6 +16,7 @@ package com.intellij.xdebugger.impl.actions.handlers; import com.intellij.lang.Language; +import com.intellij.lang.LanguageUtil; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Document; @@ -36,7 +37,6 @@ import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.frame.XValue; import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl; import com.intellij.xdebugger.impl.evaluate.XDebuggerEvaluationDialog; -import com.intellij.xdebugger.impl.ui.XDebuggerEditorBase; import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -108,11 +108,11 @@ public class XDebuggerEvaluateActionHandler extends XDebuggerActionHandler { if (stackFrame != null) { XSourcePosition position = stackFrame.getSourcePosition(); if (position != null) { - language = XDebuggerEditorBase.getFileTypeLanguage(position.getFile().getFileType()); + language = LanguageUtil.getFileLanguage(position.getFile()); } } if (language == null && file != null) { - language = XDebuggerEditorBase.getFileTypeLanguage(file.getFileType()); + language = LanguageUtil.getFileTypeLanguage(file.getFileType()); } expression = new XExpressionImpl(expression.getExpression(), language, expression.getCustomInfo(), expression.getMode()); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java index 81ac51d23337..a0900ffccb1f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerEditorBase.java @@ -17,14 +17,13 @@ package com.intellij.xdebugger.impl.ui; import com.intellij.ide.DataManager; import com.intellij.lang.Language; +import com.intellij.lang.LanguageUtil; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.ListPopup; @@ -111,7 +110,7 @@ public abstract class XDebuggerEditorBase { } DataContext dataContext = DataManager.getInstance().getDataContext(getComponent()); - return JBPopupFactory.getInstance().createActionGroupPopup("Choose language", actions, dataContext, + return JBPopupFactory.getInstance().createActionGroupPopup("Choose Language", actions, dataContext, JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false); } @@ -156,10 +155,10 @@ public abstract class XDebuggerEditorBase { Language language = text.getLanguage(); if (language == null) { if (mySourcePosition != null) { - language = getFileTypeLanguage(mySourcePosition.getFile().getFileType()); + language = LanguageUtil.getFileLanguage(mySourcePosition.getFile()); } if (language == null) { - language = getFileTypeLanguage(getEditorsProvider().getFileType()); + language = LanguageUtil.getFileTypeLanguage(getEditorsProvider().getFileType()); } } text = new XExpressionImpl(text.getExpression(), language, text.getCustomInfo(), getMode()); @@ -182,14 +181,6 @@ public abstract class XDebuggerEditorBase { doSetText(text); } - @Nullable - public static Language getFileTypeLanguage(@Nullable FileType fileType) { - if (fileType instanceof LanguageFileType) { - return ((LanguageFileType)fileType).getLanguage(); - } - return null; - } - public abstract XExpression getExpression(); @Nullable diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/intellij/codeInspection/booleanIsAlwaysInverted/BooleanMethodIsAlwaysInvertedInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/intellij/codeInspection/booleanIsAlwaysInverted/BooleanMethodIsAlwaysInvertedInspectionBase.java index ab9056eb86bb..7000ea80c1f4 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/intellij/codeInspection/booleanIsAlwaysInverted/BooleanMethodIsAlwaysInvertedInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/intellij/codeInspection/booleanIsAlwaysInverted/BooleanMethodIsAlwaysInvertedInspectionBase.java @@ -193,7 +193,7 @@ class BooleanMethodIsAlwaysInvertedInspectionBase extends GlobalJavaBatchInspect if (refElement instanceof RefMethod) { final PsiElement element = refElement.getElement(); if (!(element instanceof PsiMethod)) return; - if (((PsiMethod)element).getReturnType() != PsiType.BOOLEAN) return; + if (!PsiType.BOOLEAN.equals(((PsiMethod)element).getReturnType())) return; refElement.putUserData(ALWAYS_INVERTED, Boolean.TRUE); //initial mark boolean methods } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnpredictableBigDecimalConstructorCallInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnpredictableBigDecimalConstructorCallInspection.java index 144c50672847..60c761b1e01e 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnpredictableBigDecimalConstructorCallInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnpredictableBigDecimalConstructorCallInspection.java @@ -160,7 +160,7 @@ public class UnpredictableBigDecimalConstructorCallInspection final PsiParameter[] parameters = parameterList.getParameters(); final PsiParameter firstParameter = parameters[0]; final PsiType type = firstParameter.getType(); - if (type != PsiType.DOUBLE) { + if (!PsiType.DOUBLE.equals(type)) { return; } final PsiExpressionList argumentList = expression.getArgumentList(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ParenthesesUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ParenthesesUtils.java index 357ff9b26fb5..d4be1fb565ff 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ParenthesesUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ParenthesesUtils.java @@ -137,9 +137,9 @@ public class ParenthesesUtils { return false; } if (JavaTokenType.PLUS == tokenType || JavaTokenType.ASTERISK == tokenType) { - return primitiveType != PsiType.FLOAT && primitiveType != PsiType.DOUBLE; + return !PsiType.FLOAT.equals(primitiveType) && !PsiType.DOUBLE.equals(primitiveType); } else if (JavaTokenType.EQEQ == tokenType || JavaTokenType.NE == tokenType) { - return primitiveType == PsiType.BOOLEAN; + return PsiType.BOOLEAN.equals(primitiveType); } else if (JavaTokenType.AND == tokenType || JavaTokenType.OR == tokenType || JavaTokenType.XOR == tokenType) { return true; } else if (JavaTokenType.OROR == tokenType || JavaTokenType.ANDAND == tokenType) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java index 589d8d8b50d1..fed240173dda 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java @@ -445,7 +445,7 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { final PsiExpression[] arguments = argumentList.getExpressions(); if (arguments.length == 3) { return arguments[0].getType() instanceof PsiArrayType && - arguments[1].getType() == PsiType.INT && arguments[2].getType() == PsiType.INT; + PsiType.INT.equals(arguments[1].getType()) && PsiType.INT.equals(arguments[2].getType()); } return arguments.length == 1; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/StaticInitializerReferencesSubClassInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/StaticInitializerReferencesSubClassInspection.java index 3cc2178e793f..d68ab88eb015 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/StaticInitializerReferencesSubClassInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/StaticInitializerReferencesSubClassInspection.java @@ -20,7 +20,10 @@ import com.intellij.codeInspection.ProblemsHolder; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -68,7 +71,7 @@ public class StaticInitializerReferencesSubClassInspection extends BaseJavaBatch if (element instanceof PsiClass || element instanceof PsiReferenceParameterList || element instanceof PsiTypeElement) return; PsiClass targetClass = extractClass(element); - if (targetClass != null && !(targetClass instanceof PsiAnonymousClass) && targetClass.isInheritor(baseClass, true)) { + if (targetClass != null && targetClass.isInheritor(baseClass, true) && !hasSingleInitializationPlace(targetClass)) { PsiElement problemElement = calcProblemElement(element); if (problemElement != null) { result.set(Pair.create(problemElement, targetClass)); @@ -81,6 +84,23 @@ public class StaticInitializerReferencesSubClassInspection extends BaseJavaBatch return result.get(); } + private static boolean hasSingleInitializationPlace(@NotNull PsiClass targetClass) { + if (targetClass instanceof PsiAnonymousClass) return true; + if (!targetClass.hasModifierProperty(PsiModifier.PRIVATE)) return false; + + PsiFile file = targetClass.getContainingFile(); + if (file == null) return false; + + LocalSearchScope scope = new LocalSearchScope(file); + return ReferencesSearch.search(targetClass, scope).forEach(new Processor() { + int count = 0; + @Override + public boolean process(PsiReference reference) { + return ++count < 2; + } + }); + } + @Nullable private static PsiElement calcProblemElement(PsiElement element) { if (element instanceof PsiNewExpression) return calcProblemElement(((PsiNewExpression)element).getClassOrAnonymousClassReference()); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspection.java index c51b0735d285..b160dea1970d 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspection.java @@ -58,7 +58,7 @@ public class BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspection modifierList.setModifierProperty(PsiModifier.STATIC, true); } - if (method.getReturnType() != PsiType.VOID) { + if (!PsiType.VOID.equals(method.getReturnType())) { ChangeSignatureProcessor csp = new ChangeSignatureProcessor(project, method, false, PsiModifier.PUBLIC, method.getName(), PsiType.VOID, new ParameterInfoImpl[0]); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/StaticInitializerReferencesSubClass/StaticInitializer.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/StaticInitializerReferencesSubClass/StaticInitializer.java index 21abd1631691..f5cc496d9d95 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/StaticInitializerReferencesSubClass/StaticInitializer.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/StaticInitializerReferencesSubClass/StaticInitializer.java @@ -4,17 +4,31 @@ class Super { static final Sub C3; static final Sub C4 = SubFactory.create(); static final String C5 = SubFactory.create().toString(); + static Super USED_PRIVATE = new MyUsedSub(); static Object OK_INSIDE_ANONYMOUS = new Object() {{ Sub s = new Sub(); }}; static Object OK_UNRELATED = "abc"; static Super OK_SAME = new Super(); static Super OK_SAME_ANONYMOUS = new Super(){}; static Sub[] OK_ARRAY = new Sub[3]; + static Super OK_PRIVATE = new MySub(); static java.util.List OK_GENERICS = new java.util.ArrayList(); static { C3 = new Sub(); } + + static void foo() { + MyUsedSub.foo(); + } + + private static class MySub extends Super { } + private static class MyUsedSub extends Super { + static void foo() { + System.out.println("hello"); + } + + } } class Sub extends Super implements Intf { diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java index 75c1ebc8a3c1..936efe6b485e 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java @@ -60,7 +60,7 @@ public class SubstitutedExpressionEvaluationHelper { final PsiMethodCallExpression c = (PsiMethodCallExpression)o; final PsiMethod m = (PsiMethod)c.getMethodExpression().resolve(); final PsiType returnType = m != null? m.getReturnType() : null; - if (returnType != null && returnType != PsiType.VOID) { + if (returnType != null && !PsiType.VOID.equals(returnType)) { // find substitution final Object substituted = calcSubstituted(m); if (substituted != null) return substituted; diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java index d0f56b8cc305..cc4014728475 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java @@ -15,7 +15,10 @@ */ package com.siyeh.ipp.equality; -import com.intellij.psi.*; +import com.intellij.psi.JavaTokenType; +import com.intellij.psi.PsiBinaryExpression; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; import com.intellij.psi.tree.IElementType; import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ig.PsiReplacementUtil; @@ -44,46 +47,31 @@ public class ReplaceEqualityWithEqualsIntention extends MutablyNamedIntention { return new ObjectEqualityPredicate(); } - public void processIntention(PsiElement element) { + public void processIntention(@NotNull PsiElement element) { final PsiBinaryExpression exp = (PsiBinaryExpression)element; final PsiExpression lhs = exp.getLOperand(); final PsiExpression rhs = exp.getROperand(); if (rhs == null) { return; } - final PsiExpression strippedLhs = - ParenthesesUtils.stripParentheses(lhs); + final PsiExpression strippedLhs = ParenthesesUtils.stripParentheses(lhs); if (strippedLhs == null) { return; } - final PsiExpression strippedRhs = - ParenthesesUtils.stripParentheses(rhs); + final PsiExpression strippedRhs = ParenthesesUtils.stripParentheses(rhs); if (strippedRhs == null) { return; } - final IElementType tokenType = exp.getOperationTokenType(); + final String lhText = strippedLhs.getText(); + final String rhText = strippedRhs.getText(); + + final String prefix = exp.getOperationTokenType().equals(JavaTokenType.EQEQ) ? "" : "!"; @NonNls final String expString; - if (tokenType.equals(JavaTokenType.EQEQ)) { - if (ParenthesesUtils.getPrecedence(strippedLhs) > - ParenthesesUtils.METHOD_CALL_PRECEDENCE) { - expString = '(' + strippedLhs.getText() + ").equals(" + - strippedRhs.getText() + ')'; - } - else { - expString = strippedLhs.getText() + ".equals(" + - strippedRhs.getText() + ')'; - } + if (ParenthesesUtils.getPrecedence(strippedLhs) > ParenthesesUtils.METHOD_CALL_PRECEDENCE) { + expString = prefix + '(' + lhText + ").equals(" + rhText + ')'; } else { - if (ParenthesesUtils.getPrecedence(strippedLhs) > - ParenthesesUtils.METHOD_CALL_PRECEDENCE) { - expString = "!(" + strippedLhs.getText() + ").equals(" + - strippedRhs.getText() + ')'; - } - else { - expString = '!' + strippedLhs.getText() + ".equals(" + - strippedRhs.getText() + ')'; - } + expString = prefix + lhText + ".equals(" + rhText + ')'; } PsiReplacementUtil.replaceExpression(exp, expString); } diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index e1918e6fc5fa..1ee6118bbf06 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -133,6 +133,10 @@ groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.StatefulEpInspection"/> + diff --git a/plugins/devkit/resources/inspectionDescriptions/UsePrimitiveTypes.html b/plugins/devkit/resources/inspectionDescriptions/UsePrimitiveTypes.html new file mode 100644 index 000000000000..aadc3c90ab8c --- /dev/null +++ b/plugins/devkit/resources/inspectionDescriptions/UsePrimitiveTypes.html @@ -0,0 +1,5 @@ + + +Primitive types should be compared with .equals due to java 8 type annotations also applicable to primitive types + + \ No newline at end of file diff --git a/plugins/devkit/src/dom/impl/ExtensionDomExtender.java b/plugins/devkit/src/dom/impl/ExtensionDomExtender.java index 97546dd5e704..2315cb045499 100644 --- a/plugins/devkit/src/dom/impl/ExtensionDomExtender.java +++ b/plugins/devkit/src/dom/impl/ExtensionDomExtender.java @@ -158,7 +158,7 @@ public class ExtensionDomExtender extends DomExtender { Class clazz = String.class; if (withElement != null || isClassField(fieldName)) { clazz = PsiClass.class; - } else if (field.getType() == PsiType.BOOLEAN) { + } else if (PsiType.BOOLEAN.equals(field.getType())) { clazz = Boolean.class; } final DomExtension extension = diff --git a/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java b/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java index 7aeb7a047046..70d8cf939d18 100644 --- a/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java +++ b/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java @@ -102,7 +102,7 @@ public class DevKitImplicitUsageProvider implements ImplicitUsageProvider { private static boolean isDomElementVisitorMethod(PsiMethod method, PsiClass containingClass) { - if (method.getReturnType() != PsiType.VOID || + if (!PsiType.VOID.equals(method.getReturnType()) || !method.getName().startsWith("visit") || method.getParameterList().getParametersCount() != 1 || !InheritanceUtil.isInheritor(containingClass, "com.intellij.util.xml.DomElementVisitor")) { diff --git a/plugins/devkit/src/inspections/StatefulEpInspection.java b/plugins/devkit/src/inspections/StatefulEpInspection.java index ee97296bf201..5b102c4fd4e7 100644 --- a/plugins/devkit/src/inspections/StatefulEpInspection.java +++ b/plugins/devkit/src/inspections/StatefulEpInspection.java @@ -38,7 +38,7 @@ public class StatefulEpInspection extends DevKitInspectionBase { if (fields.length == 0) return super.checkClass(psiClass, manager, isOnTheFly); final boolean isQuickFix = InheritanceUtil.isInheritor(psiClass, LocalQuickFix.class.getCanonicalName()); final boolean isProjectComponent = InheritanceUtil.isInheritor(psiClass, ProjectComponent.class.getCanonicalName()); - if (isQuickFix || ExtensionPointLocator.isImplementedEp(psiClass)) { + if (isQuickFix || ExtensionPointLocator.isRegisteredExtension(psiClass)) { List result = ContainerUtil.newArrayList(); for (final PsiField field : fields) { for (Class c : new Class[]{PsiElement.class, PsiReference.class, Project.class}) { diff --git a/plugins/devkit/src/inspections/internal/UsePrimitiveTypesInspection.java b/plugins/devkit/src/inspections/internal/UsePrimitiveTypesInspection.java new file mode 100644 index 000000000000..46a8e5c928ba --- /dev/null +++ b/plugins/devkit/src/inspections/internal/UsePrimitiveTypesInspection.java @@ -0,0 +1,131 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.devkit.inspections.internal; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiUtil; +import com.siyeh.IntentionPowerPackBundle; +import com.siyeh.ig.PsiReplacementUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +public class UsePrimitiveTypesInspection extends InternalInspection { + @Override + public PsiElementVisitor buildInternalVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) { + return new JavaElementVisitor() { + @Override + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final IElementType tokenType = expression.getOperationTokenType(); + if (tokenType.equals(JavaTokenType.EQEQ) || tokenType.equals(JavaTokenType.NE)) { + final PsiExpression lOperand = expression.getLOperand(); + final PsiExpression rOperand = expression.getROperand(); + if (rOperand != null && (isPrimitiveTypeRef(lOperand) || isPrimitiveTypeRef(rOperand))) { + final String name; + if (JavaTokenType.NE.equals(tokenType)) { + name = IntentionPowerPackBundle.message("replace.equality.with.not.equals.intention.name"); + } + else { + name = IntentionPowerPackBundle.message("replace.equality.with.equals.intention.name"); + } + holder.registerProblem(expression.getOperationSign(), + "Primitive types should be compared with .equals", + new ReplaceEqualityWithEqualsFix(name)); + } + } + } + }; + } + + private static boolean isPrimitiveTypeRef(PsiExpression expression) { + if (expression instanceof PsiReferenceExpression) { + final PsiElement target = ((PsiReferenceExpression)expression).resolve(); + if (target instanceof PsiField) { + final PsiClass containingClass = ((PsiField)target).getContainingClass(); + return containingClass != null && + PsiType.class.getName().equals(containingClass.getQualifiedName()) && + !"NULL".equals(((PsiField)target).getName()); + } + } + return false; + } + + private static class ReplaceEqualityWithEqualsFix implements LocalQuickFix { + private final String myName; + + public ReplaceEqualityWithEqualsFix(String name) { + myName = name; + } + + @Nls + @NotNull + @Override + public String getName() { + return myName; + } + + @Nls + @NotNull + @Override + public String getFamilyName() { + return "Replace equality with .equals"; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiElement psiElement = descriptor.getPsiElement(); + if (psiElement instanceof PsiJavaToken) { + + final IElementType tokenType = ((PsiJavaToken)psiElement).getTokenType(); + final String prefix; + if (tokenType.equals(JavaTokenType.EQEQ)) { + prefix = ""; + } + else if (tokenType.equals(JavaTokenType.NE)) { + prefix = "!"; + } + else { + return; + } + + final PsiElement parent = psiElement.getParent(); + if (parent instanceof PsiBinaryExpression) { + final PsiExpression rOperand = ((PsiBinaryExpression)parent).getROperand(); + final PsiExpression lOperand = ((PsiBinaryExpression)parent).getLOperand(); + if (rOperand != null) { + final boolean flip = isPrimitiveTypeRef(rOperand); + if (flip || isPrimitiveTypeRef(lOperand)) { + final String rText = PsiUtil.skipParenthesizedExprUp(rOperand).getText(); + final String lText = PsiUtil.skipParenthesizedExprUp(lOperand).getText(); + + final String lhText = flip ? rText : lText; + final String rhText = flip ? lText : rText; + + @NonNls final String expString = prefix + lhText + ".equals(" + rhText + ')'; + PsiReplacementUtil.replaceExpression((PsiBinaryExpression)parent, expString); + } + } + } + } + } + } +} diff --git a/plugins/devkit/src/util/ExtensionPointLocator.java b/plugins/devkit/src/util/ExtensionPointLocator.java index 4f7beac31eda..34ba0c37cf2f 100644 --- a/plugins/devkit/src/util/ExtensionPointLocator.java +++ b/plugins/devkit/src/util/ExtensionPointLocator.java @@ -92,7 +92,7 @@ public class ExtensionPointLocator { return GlobalSearchScope.filesScope(project, candidates); } - public static boolean isImplementedEp(@NotNull PsiClass psiClass) { + public static boolean isRegisteredExtension(@NotNull PsiClass psiClass) { String name = psiClass.getQualifiedName(); if (name == null) return false; diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java index 27e576979158..892b7e55291f 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/EclipseClasspathWriter.java @@ -28,6 +28,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import gnu.trove.THashMap; import org.jdom.Element; @@ -39,7 +40,6 @@ import org.jetbrains.idea.eclipse.EclipseXml; import org.jetbrains.idea.eclipse.IdeaXml; import org.jetbrains.idea.eclipse.config.EclipseModuleManagerImpl; -import java.util.Arrays; import java.util.Map; public class EclipseClasspathWriter { @@ -90,7 +90,7 @@ public class EclipseClasspathWriter { private void createClasspathEntry(@NotNull OrderEntry entry, @NotNull Element classpathRoot, @NotNull final ModuleRootModel model) throws ConversionException { EclipseModuleManager eclipseModuleManager = EclipseModuleManagerImpl.getInstance(entry.getOwnerModule()); if (entry instanceof ModuleSourceOrderEntry) { - boolean shouldPlaceSeparately = eclipseModuleManager.isExpectedModuleSourcePlace(Arrays.binarySearch(model.getOrderEntries(), entry)); + boolean shouldPlaceSeparately = eclipseModuleManager.isExpectedModuleSourcePlace(ArrayUtil.find(model.getOrderEntries(), entry)); for (ContentEntry contentEntry : model.getContentEntries()) { VirtualFile contentRoot = contentEntry.getFile(); for (SourceFolder sourceFolder : contentEntry.getSourceFolders()) { diff --git a/plugins/git4idea/lib/trilead-ssh2-src.zip b/plugins/git4idea/lib/trilead-ssh2-src.zip index 02c3bfa5538f..2a8472b2d245 100644 Binary files a/plugins/git4idea/lib/trilead-ssh2-src.zip and b/plugins/git4idea/lib/trilead-ssh2-src.zip differ diff --git a/plugins/git4idea/lib/trilead-ssh2.jar b/plugins/git4idea/lib/trilead-ssh2.jar index d22178a73746..e19bd37f7429 100644 Binary files a/plugins/git4idea/lib/trilead-ssh2.jar and b/plugins/git4idea/lib/trilead-ssh2.jar differ diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/events/AfterTestEvent.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/events/AfterTestEvent.java index 6909af18b8c4..2123586e9fa8 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/events/AfterTestEvent.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/events/AfterTestEvent.java @@ -23,6 +23,7 @@ import com.intellij.util.ObjectUtils; import org.jetbrains.plugins.gradle.execution.test.runner.GradleTestsExecutionConsole; import org.jetbrains.plugins.gradle.util.XmlXpathHelper; +import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -54,14 +55,14 @@ public class AfterTestEvent extends AbstractTestEvent { catch (NumberFormatException ignored) { } + final CompositeRunnable runInEdt = new CompositeRunnable(); final TestEventResult result = getTestEventResultType(eventXml); switch (result) { case SUCCESS: - addToInvokeLater(new Runnable() { + runInEdt.add(new Runnable() { @Override public void run() { testProxy.setFinished(); - getResultsViewer().onTestFinished(testProxy); } }); break; @@ -102,7 +103,7 @@ public class AfterTestEvent extends AbstractTestEvent { } final Couple finalComparisonPair = comparisonPair; - addToInvokeLater(new Runnable() { + runInEdt.add(new Runnable() { @Override public void run() { if (finalComparisonPair != null) { @@ -111,9 +112,10 @@ public class AfterTestEvent extends AbstractTestEvent { else { testProxy.setTestFailed(exceptionMsg, stackTrace, "error".equals(failureType)); } - }}); + } + }); } - addToInvokeLater(new Runnable() { + runInEdt.add(new Runnable() { @Override public void run() { getResultsViewer().onTestFailed(testProxy); @@ -121,10 +123,10 @@ public class AfterTestEvent extends AbstractTestEvent { }); break; case SKIPPED: - testProxy.setTestIgnored(null, null); - addToInvokeLater(new Runnable() { + runInEdt.add(new Runnable() { @Override public void run() { + testProxy.setTestIgnored(null, null); getResultsViewer().onTestIgnored(testProxy); } }); @@ -132,6 +134,15 @@ public class AfterTestEvent extends AbstractTestEvent { case UNKNOWN_RESULT: break; } + + runInEdt.add(new Runnable() { + @Override + public void run() { + getResultsViewer().onTestFinished(testProxy); + } + }); + + addToInvokeLater(runInEdt); } private static Couple parseComparisonMessage(String message, final String regex) { @@ -141,4 +152,13 @@ public class AfterTestEvent extends AbstractTestEvent { } return null; } + + private static class CompositeRunnable extends ArrayList implements Runnable { + @Override + public void run() { + for (Runnable runnable : this) { + runnable.run(); + } + } + } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index ff48a0fde0b8..88cedf1b1097 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -1067,7 +1067,7 @@ public class GroovyAnnotator extends GroovyElementVisitor { PsiMethod superMethod = superMethodSignature.getMethod(); PsiType declaredReturnType = superMethod.getReturnType(); PsiType superReturnType = superMethodSignature.getSubstitutor().substitute(declaredReturnType); - if (superReturnType == PsiType.VOID && method instanceof GrMethod && ((GrMethod)method).getReturnTypeElementGroovy() == null) return; + if (PsiType.VOID.equals(superReturnType) && method instanceof GrMethod && ((GrMethod)method).getReturnTypeElementGroovy() == null) return; if (superMethodSignature.isRaw()) superReturnType = TypeConversionUtil.erasure(declaredReturnType); if (returnType == null || superReturnType == null || method == superMethod) continue; PsiClass superClass = superMethod.getContainingClass(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java index 248074a55b95..7b1abd439e0d 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/noReturnMethod/MissingReturnInspection.java @@ -84,10 +84,10 @@ public class MissingReturnInspection extends GroovySuppressableInspectionTool { PsiClass resolved = ((PsiClassType)inferredReturnType).resolve(); if (resolved != null && !(resolved instanceof PsiTypeParameter)) return mustReturnValue; } - return inferredReturnType != null && inferredReturnType != PsiType.VOID ? shouldReturnValue : shouldNotReturnValue; + return inferredReturnType != null && !PsiType.VOID.equals(inferredReturnType) ? shouldReturnValue : shouldNotReturnValue; } else if (subject instanceof GrMethod) { - return ((GrMethod)subject).getReturnTypeElementGroovy() != null && ((GrMethod)subject).getReturnType() != PsiType.VOID + return ((GrMethod)subject).getReturnTypeElementGroovy() != null && !PsiType.VOID.equals(((GrMethod)subject).getReturnType()) ? mustReturnValue : shouldNotReturnValue; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/type/GroovyTypeCheckVisitor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/type/GroovyTypeCheckVisitor.java index 782f10c65d49..da729abb2ac9 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/type/GroovyTypeCheckVisitor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/type/GroovyTypeCheckVisitor.java @@ -22,7 +22,6 @@ import com.intellij.openapi.util.Condition; import com.intellij.psi.*; import com.intellij.psi.impl.PsiSubstitutorImpl; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -696,7 +695,7 @@ public class GroovyTypeCheckVisitor extends BaseInspectionVisitor { @NotNull PsiElement elementToHighlight) { if (getTupleInitializer(expression) != null) return; final PsiType returnType = PsiImplUtil.inferReturnType(expression); - if (returnType == null || returnType == PsiType.VOID) return; + if (returnType == null || PsiType.VOID.equals(returnType)) return; processAssignment(returnType, expression, elementToHighlight, "cannot.return.type", context, ApplicableTo.RETURN_VALUE); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/GroovyFindUsagesProvider.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/GroovyFindUsagesProvider.java index 60f847946239..8c57cf8dc588 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/GroovyFindUsagesProvider.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/GroovyFindUsagesProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,11 +32,6 @@ import org.jetbrains.plugins.groovy.refactoring.rename.PropertyForRename; */ public class GroovyFindUsagesProvider implements FindUsagesProvider { - public static final GroovyFindUsagesProvider INSTANCE = new GroovyFindUsagesProvider(); - - public GroovyFindUsagesProvider() { - } - @Override @Nullable public WordsScanner getWordsScanner() { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorReference.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorReference.java index 2d1810f5bfa2..e88b5e3fe191 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorReference.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorReference.java @@ -77,7 +77,7 @@ public class LiteralConstructorReference extends PsiReferenceBase.Poly myTraitTypes; - private final GrExpression myOriginal; + private GrTraitType(@NotNull PsiType[] types) { + super(types); + myExprType = types[0]; + myTraitTypes = ContainerUtil.newArrayList(types, 1, types.length); + } - private final PsiClassType myExprType; - private final List myTraitTypes; + @NotNull + public PsiType getExprType() { + return myExprType; + } - private final GlobalSearchScope myResolveScope; - - private final VolatileNotNullLazyValue myParameters = new VolatileNotNullLazyValue() { - @NotNull - @Override - protected PsiType[] compute() { - List result = ContainerUtil.newArrayList(); - ContainerUtil.addAll(result, myExprType.getParameters()); - for (PsiClassType type : myTraitTypes) { - ContainerUtil.addAll(result, type.getParameters()); - } - return result.toArray(new PsiType[result.size()]); - } - }; - - - public GrTraitType(@NotNull GrExpression original, - @NotNull PsiClassType exprType, - @NotNull List traitTypes, - @NotNull GlobalSearchScope resolveScope, LanguageLevel languageLevel) { - super(languageLevel); - myOriginal = original; - myResolveScope = resolveScope; - myExprType = exprType; - myTraitTypes = ContainerUtil.newArrayList(traitTypes); + @NotNull + public List getTraitTypes() { + return myTraitTypes; } @NotNull @Override public String getPresentableText() { - return myExprType.getPresentableText() + " as " + StringUtil.join(ContainerUtil.map(myTraitTypes, new Function() { + return myExprType.getPresentableText() + " as " + StringUtil.join(ContainerUtil.map(myTraitTypes, new Function() { @Override - public String fun(PsiClassType type) { + public String fun(PsiType type) { return type.getPresentableText(); } }), ", "); } - @NotNull - @Override - public String getCanonicalText() { - return myExprType.getCanonicalText(); - } - @NotNull @Override public String getInternalCanonicalText() { - return myExprType.getCanonicalText() + " as " + StringUtil.join(ContainerUtil.map(myTraitTypes, new Function() { + return myExprType.getCanonicalText() + " as " + StringUtil.join(ContainerUtil.map(myTraitTypes, new Function() { @Override - public String fun(PsiClassType type) { - return type.getCanonicalText(); + public String fun(PsiType type) { + return type.getInternalCanonicalText(); } }), ", "); } - @Override - public boolean isValid() { - return myExprType.isValid() && ContainerUtil.find(myTraitTypes, new Condition() { - @Override - public boolean value(PsiClassType type) { - return !type.isValid(); - } - }) == null; - } - - @Override - public boolean equalsToText(@NotNull @NonNls String text) { - return false; - } - - @NotNull - @Override - public LanguageLevel getLanguageLevel() { - return myLanguageLevel; - } - - @NotNull - @Override - public PsiClassType setLanguageLevel(@NotNull LanguageLevel languageLevel) { - return new GrTraitType(myOriginal, myExprType, myTraitTypes, myResolveScope, languageLevel); - } - + // todo move this method to org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.types.GrSafeCastExpressionImpl @Nullable - @Override - public PsiClass resolve() { - return getMockTypeDefinition(); - } - - @Override - public String getClassName() { - return null; - } - - @NotNull - @Override - public PsiType[] getParameters() { - return myParameters.getValue(); - } - - @NotNull - @Override - public PsiType[] getSuperTypes() { - PsiType[] result = new PsiType[myTraitTypes.size() + 1]; - result[0] = myExprType; - ArrayUtil.copy(myTraitTypes, result, 1); - return result; - } - - @NotNull - @Override - public ClassResolveResult resolveGenerics() { - return CachedValuesManager.getCachedValue(myOriginal, new CachedValueProvider() { - @Nullable - @Override - public Result compute() { - final GrTypeDefinition definition = new MockTypeBuilder().buildMockTypeDefinition(); - final PsiSubstitutor substitutor = new SubstitutorBuilder(definition).buildSubstitutor(); - - return Result.create(new TraitResolveResult(definition, substitutor), PsiModificationTracker.MODIFICATION_COUNT); - } - }); - } - - @NotNull - @Override - public PsiClassType rawType() { - return new GrTraitType(myOriginal, myExprType.rawType(), ContainerUtil.map(myTraitTypes, new Function() { - @Override - public PsiClassType fun(PsiClassType type) { - return type.rawType(); - } - }), myResolveScope, myLanguageLevel); - } - - @NotNull - @Override - public GlobalSearchScope getResolveScope() { - return myResolveScope; - } - - @Nullable - public GrTypeDefinition getMockTypeDefinition() { - return CachedValuesManager.getCachedValue(myOriginal, new CachedValueProvider() { - @Nullable - @Override - public Result compute() { - return Result.create(new MockTypeBuilder().buildMockTypeDefinition(), PsiModificationTracker.MODIFICATION_COUNT); - } - }); - } - - public PsiClassType getExprType() { - return myExprType; - } - - public List getTraitTypes() { - return Collections.unmodifiableList(myTraitTypes); - } - - public GrTraitType erasure() { - PsiClassType exprType = (PsiClassType)TypeConversionUtil.erasure(myExprType); - List traitTypes = ContainerUtil.map(myTraitTypes, new Function() { - @Override - public PsiClassType fun(PsiClassType type) { - return (PsiClassType)TypeConversionUtil.erasure(type); - } - }); - return new GrTraitType(myOriginal, exprType, traitTypes, myResolveScope, LanguageLevel.JDK_1_5); - } - - @Nullable - public static GrTraitType createTraitClassType(@NotNull GrSafeCastExpression safeCastExpression) { + public static PsiType createTraitClassType(@NotNull GrSafeCastExpression safeCastExpression) { GrExpression operand = safeCastExpression.getOperand(); PsiType exprType = operand.getType(); - if (!(exprType instanceof PsiClassType)) return null; + if (!(exprType instanceof PsiClassType) && !(exprType instanceof GrTraitType)) return null; GrTypeElement typeElement = safeCastExpression.getCastTypeElement(); if (typeElement == null) return null; PsiType type = typeElement.getType(); if (!GrTraitUtil.isTrait(PsiTypesUtil.getPsiClass(type))) return null; - return new GrTraitType(safeCastExpression, ((PsiClassType)exprType), Collections.singletonList((PsiClassType)type), safeCastExpression.getResolveScope(), - LanguageLevel.JDK_1_5); + return createTraitClassType(exprType, ContainerUtil.newSmartList(type)); } - - @NotNull - public static GrTraitType createTraitClassType(@NotNull GrExpression context, - @NotNull PsiClassType exprType, - @NotNull List traitTypes, - @NotNull GlobalSearchScope resolveScope) { - return new GrTraitType(context, exprType, traitTypes, resolveScope, LanguageLevel.JDK_1_5); + public static PsiType createTraitClassType(@NotNull PsiType type, @NotNull List traits) { + return createTraitClassType(ContainerUtil.prepend(traits, type)); } - private static class TraitResolveResult implements ClassResolveResult { - - private final GrTypeDefinition myDefinition; - private final PsiSubstitutor mySubstitutor; - - public TraitResolveResult(GrTypeDefinition definition, PsiSubstitutor substitutor) { - myDefinition = definition; - mySubstitutor = substitutor; - } - - @Override - public GrTypeDefinition getElement() { - return myDefinition; - } - - @NotNull - @Override - public PsiSubstitutor getSubstitutor() { - return mySubstitutor; - } - - @Override - public boolean isPackagePrefixPackageReference() { - return false; - } - - @Override - public boolean isAccessible() { - return true; - } - - @Override - public boolean isStaticsScopeCorrect() { - return true; - } - - @Override - public PsiElement getCurrentFileResolveScope() { - return null; - } - - @Override - public boolean isValidResult() { - return true; - } - } - - private class MockTypeBuilder { - GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myOriginal.getProject()); - - @Nullable - public GrTypeDefinition buildMockTypeDefinition() { - try { - - StringBuilder buffer = new StringBuilder("class _____________Temp___________ "); - prepareGenerics(buffer); - buffer.append(" extends Super implements Trait {}"); - GrTypeDefinition definition = factory.createTypeDefinition(buffer.toString()); - replaceReferenceWith(definition.getExtendsClause(), myExprType); - addReferencesWith(definition.getImplementsClause(), myTraitTypes, myExprType.getParameterCount()); - return definition; + public static PsiType createTraitClassType(@NotNull List types) { + final Set flattened = flatten(types.toArray(createArray(types.size())), new LinkedHashSet() { + @Override + public boolean add(PsiType type) { + remove(type); + return super.add(type); } - catch (IncorrectOperationException e) { - return null; - } - } - - private void prepareGenerics(StringBuilder buffer) { - int count = myExprType.getParameterCount(); - for (PsiClassType trait : myTraitTypes) { - count += trait.getParameterCount(); - } - if (count == 0) return; - - buffer.append('<'); - for (int i = 0; i < count; i++) { - buffer.append("T").append(i).append(","); - } - buffer.replace(buffer.length() - 1, buffer.length(), ">"); - } - - private void addReferencesWith(@Nullable GrImplementsClause clause, @NotNull List traitTypes, int parameterOffset) { - LOG.assertTrue(clause != null); - clause.getReferenceElementsGroovy()[0].delete(); - for (PsiClassType type : traitTypes) { - processType(clause, type, parameterOffset); - parameterOffset += type.getParameterCount(); - } - } - - private void replaceReferenceWith(@Nullable GrReferenceList clause, @NotNull PsiClassType type) { - LOG.assertTrue(clause != null); - clause.getReferenceElementsGroovy()[0].delete(); - processType(clause, type, 0); - } - - private void processType(@NotNull GrReferenceList clause, @NotNull PsiClassType type, int parameterOffset) { - PsiClass resolved = type.resolve(); - if (resolved != null) { - String qname = resolved.getQualifiedName(); - StringBuilder buffer = new StringBuilder(); - buffer.append(qname); - int parameterCount = type.getParameterCount(); - if (parameterCount > 0) { - buffer.append('<'); - for (int i = 0; i < parameterCount; i++) { - buffer.append("T").append(parameterOffset + i).append(','); - } - buffer.replace(buffer.length() - 1, buffer.length(), ">"); - } - - GrCodeReferenceElement ref = factory.createCodeReferenceElementFromText(buffer.toString()); - clause.add(ref); - } - } - } - - private class SubstitutorBuilder { - - private final GrTypeParameter[] myParameters; - private int myOffset = 0; - - public SubstitutorBuilder(@NotNull GrTypeDefinition definition) { - GrTypeParameterList typeParameterList = definition.getTypeParameterList(); - myParameters = typeParameterList != null ? typeParameterList.getTypeParameters() : GrTypeParameter.EMPTY_ARRAY; - } - - @NotNull - public PsiSubstitutor buildSubstitutor() { - if (myParameters.length == 0) return PsiSubstitutor.EMPTY; - - Map map = ContainerUtil.newLinkedHashMap(); - putMappingAndReturnOffset(map, myExprType); - for (PsiClassType type : myTraitTypes) { - putMappingAndReturnOffset(map, type); - } - - return JavaPsiFacade.getElementFactory(myOriginal.getProject()).createSubstitutor(map); - } - - private void putMappingAndReturnOffset(@NotNull Map map, @NotNull PsiClassType type) { - PsiType[] args = type.getParameters(); - for (int i = 0; i < args.length; i++) { - map.put(myParameters[myOffset + i], args[i]); - } - myOffset += args.length; - } + }); + final PsiType[] conjuncts = flattened.toArray(createArray(flattened.size())); + if (conjuncts.length == 1) return conjuncts[0]; + return new GrTraitType(conjuncts); } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.java index 13159892a3ee..fdd9b1129fc4 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,9 +34,6 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint; import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; -import java.util.List; -import java.util.ListIterator; - /** * @author Medvedev Max */ @@ -119,7 +116,7 @@ public class GrReferenceResolveRunner { private boolean processQualifier(@NotNull GrExpression qualifier) { PsiType qualifierType = qualifier.getType(); ResolveState state = ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier); - if (qualifierType == null || qualifierType == PsiType.VOID) { + if (qualifierType == null || PsiType.VOID.equals(qualifierType)) { if (qualifier instanceof GrReferenceExpression) { PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); if (resolved != null && !resolved.processDeclarations(processor, state, null, place)) return false; @@ -129,11 +126,6 @@ public class GrReferenceResolveRunner { } } } - else if (qualifierType instanceof PsiIntersectionType) { - for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) { - if (!processQualifierType(conjunct, state)) return false; - } - } else { if (!processQualifierType(qualifierType, state)) return false; if (qualifier instanceof GrReferenceExpression && !PsiUtil.isSuperReference(qualifier) && !PsiUtil.isInstanceThisRef(qualifier)) { @@ -174,20 +166,16 @@ public class GrReferenceResolveRunner { ? ((PsiDisjunctionType)originalQualifierType).getLeastUpperBound() : originalQualifierType; - if (qualifierType instanceof PsiIntersectionType) { + if (qualifierType instanceof GrTraitType) { + return processTraitType((GrTraitType)qualifierType, state); + } + else if (qualifierType instanceof PsiIntersectionType) { for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) { if (!processQualifierType(conjunct, state)) return false; } return true; } - if (qualifierType instanceof GrTraitType) { - if (!processTraitType((GrTraitType)qualifierType, state)) { - return false; - } - return true; - } - if (qualifierType instanceof PsiClassType) { PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType)qualifierType).resolveGenerics(); PsiClass qualifierClass = qualifierResult.getElement(); @@ -217,24 +205,10 @@ public class GrReferenceResolveRunner { } private boolean processTraitType(@NotNull GrTraitType traitType, @NotNull ResolveState state) { - GrTypeDefinition mockDefinition = traitType.getMockTypeDefinition(); - if (mockDefinition != null) { - if (!mockDefinition.processDeclarations(processor, state, null, place)) { - return false; - } + final PsiType[] conjuncts = traitType.getConjuncts(); + for (int i = conjuncts.length - 1; i >= 0; i--) { + if (!processQualifierType(conjuncts[i], state)) return false; } - else { - PsiClassType exprType = traitType.getExprType(); - - if (!processQualifierType(exprType, state)) return false; - - List traitTypes = traitType.getTraitTypes(); - for (ListIterator iterator = traitTypes.listIterator(); iterator.hasPrevious(); ) { - PsiClassType type = iterator.previous(); - if (!processQualifierType(type, state)) return false; - } - } - return true; } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index 675b413ea83f..7eb1ac7654b2 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -310,9 +310,8 @@ public class TypesUtil { } if (rType instanceof GrTraitType) { - if (isAssignableWithoutConversions(lType, ((GrTraitType)rType).getExprType(), context)) return true; - for (PsiClassType trait : ((GrTraitType)rType).getTraitTypes()) { - if (isAssignableWithoutConversions(lType, trait, context)) return true; + for (PsiType type : ((GrTraitType)rType).getConjuncts()) { + if (isAssignableWithoutConversions(lType, type, context)) return true; } return false; } @@ -441,7 +440,7 @@ public class TypesUtil { @NotNull PsiManager manager, @NotNull GlobalSearchScope resolveScope, boolean boxVoid) { - if (result instanceof PsiPrimitiveType && (boxVoid || result != PsiType.VOID)) { + if (result instanceof PsiPrimitiveType && (boxVoid || !PsiType.VOID.equals(result))) { PsiPrimitiveType primitive = (PsiPrimitiveType)result; String boxedTypeName = primitive.getBoxedTypeName(); if (boxedTypeName != null) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrWithTraitTypeCalculator.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrWithTraitTypeCalculator.java index e53d5e394646..2c0459f20c58 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrWithTraitTypeCalculator.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrWithTraitTypeCalculator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,22 +51,22 @@ public class GrWithTraitTypeCalculator extends GrCallExpressionTypeCalculator { if (originalObject == null) return null; PsiType invokedType = originalObject.getType(); - if (!(invokedType instanceof PsiClassType)) return null; + if (!(invokedType instanceof PsiClassType) && !(invokedType instanceof GrTraitType)) return null; PsiClass containingClass = resolvedMethod.getContainingClass(); if (containingClass == null || !GroovyCommonClassNames.DEFAULT_GROOVY_METHODS.equals(containingClass.getQualifiedName())) return null; - List traits = ContainerUtil.newArrayList(); + List traits = ContainerUtil.newArrayList(); GrExpression[] args = callExpression.getArgumentList().getExpressionArguments(); for (GrExpression arg : args) { PsiType type = arg.getType(); PsiType classItem = PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_LANG_CLASS, 0, false); PsiClass psiClass = PsiTypesUtil.getPsiClass(classItem); if (GrTraitUtil.isTrait(psiClass)) { - traits.add((PsiClassType)classItem); + traits.add(classItem); } } - return GrTraitType.createTraitClassType(callExpression, (PsiClassType)invokedType, traits, callExpression.getResolveScope()); + return GrTraitType.createTraitClassType(invokedType, traits); } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java index 78aa01b21860..f1e69345f5bf 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -67,7 +67,7 @@ public class GrSafeCastExpressionImpl extends GrExpressionImpl implements GrSafe return JavaPsiFacade.getElementFactory(cast.getProject()).createType(resolved, substitutor); } - GrTraitType traitClassType = GrTraitType.createTraitClassType(cast); + PsiType traitClassType = GrTraitType.createTraitClassType(cast); if (traitClassType != null) { return traitClassType; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrBooleanTypeConverter.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrBooleanTypeConverter.java index a03741f1df47..444fe15ee619 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrBooleanTypeConverter.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrBooleanTypeConverter.java @@ -38,7 +38,7 @@ public class GrBooleanTypeConverter extends GrTypeConverter { @NotNull PsiType actualType, @NotNull GroovyPsiElement context, @NotNull ApplicableTo currentPosition) { - if (PsiType.BOOLEAN != TypesUtil.unboxPrimitiveTypeWrapper(targetType)) return null; + if (!PsiType.BOOLEAN.equals(TypesUtil.unboxPrimitiveTypeWrapper(targetType))) return null; if (PsiType.NULL == actualType) { switch (currentPosition) { case METHOD_PARAMETER: diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrCharConverter.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrCharConverter.java index a8eb4df89648..495f8809af71 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrCharConverter.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrCharConverter.java @@ -42,14 +42,14 @@ public class GrCharConverter extends GrTypeConverter { @NotNull PsiType rType, @NotNull GroovyPsiElement context, @NotNull ApplicableTo currentPosition) { - if (PsiType.CHAR != TypesUtil.unboxPrimitiveTypeWrapper(lType)) return null; - if (PsiType.CHAR == TypesUtil.unboxPrimitiveTypeWrapper(rType)) return ConversionResult.OK; + if (!PsiType.CHAR.equals(TypesUtil.unboxPrimitiveTypeWrapper(lType))) return null; + if (PsiType.CHAR.equals(TypesUtil.unboxPrimitiveTypeWrapper(rType))) return ConversionResult.OK; // can cast and assign numeric types to char if (TypesUtil.isNumericType(rType)) { if (rType instanceof PsiPrimitiveType || currentPosition != ApplicableTo.EXPLICIT_CAST && TypesUtil.unboxPrimitiveTypeWrapper(rType) instanceof PsiPrimitiveType) { - return PsiType.CHAR == lType ? ConversionResult.OK : ConversionResult.ERROR; + return PsiType.CHAR.equals(lType) ? ConversionResult.OK : ConversionResult.ERROR; } else { // BigDecimal && BigInteger @@ -76,7 +76,7 @@ public class GrCharConverter extends GrTypeConverter { } } - if (PsiType.BOOLEAN == TypesUtil.unboxPrimitiveTypeWrapper(rType)) { + if (PsiType.BOOLEAN.equals(TypesUtil.unboxPrimitiveTypeWrapper(rType))) { switch (currentPosition) { case EXPLICIT_CAST: return ConversionResult.ERROR; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrNullVoidConverter.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrNullVoidConverter.java index 59253816aa15..e8c0ae862070 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrNullVoidConverter.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/GrNullVoidConverter.java @@ -51,27 +51,27 @@ public class GrNullVoidConverter extends GrTypeConverter { final PsiClassType objectType = TypesUtil.getJavaLangObject(context); if (currentPosition == ApplicableTo.EXPLICIT_CAST) { - if (TypesUtil.unboxPrimitiveTypeWrapper(targetType) == PsiType.VOID) { // cast to V(v)oid + if (PsiType.VOID.equals(TypesUtil.unboxPrimitiveTypeWrapper(targetType))) { // cast to V(v)oid if (actualType.equals(objectType)) return ConversionResult.WARNING; // cast Object to V(v)oid compiles but fails at runtime - if (targetType == PsiType.VOID) { // cast to void + if (PsiType.VOID.equals(targetType)) { // cast to void // can cast void to void only - return actualType == PsiType.VOID ? ConversionResult.OK : ConversionResult.ERROR; + return PsiType.VOID.equals(actualType) ? ConversionResult.OK : ConversionResult.ERROR; } else { // cast to Void // can cast Void, void and null to Void - return actualType == PsiType.NULL || TypesUtil.unboxPrimitiveTypeWrapper(actualType) == PsiType.VOID + return actualType == PsiType.NULL || PsiType.VOID.equals(TypesUtil.unboxPrimitiveTypeWrapper(actualType)) ? ConversionResult.OK : ConversionResult.ERROR; } } } else if (currentPosition == ApplicableTo.RETURN_VALUE) { - if (targetType.equals(objectType) && actualType == PsiType.VOID) { + if (targetType.equals(objectType) && PsiType.VOID.equals(actualType)) { return ConversionResult.OK; // can return void from Object } } - if (actualType == PsiType.VOID) { + if (PsiType.VOID.equals(actualType)) { switch (currentPosition) { case EXPLICIT_CAST: return ConversionResult.ERROR; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyPropertyUtils.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyPropertyUtils.java index 48bee8fe3807..7bbe205e61c4 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyPropertyUtils.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyPropertyUtils.java @@ -217,7 +217,7 @@ public class GroovyPropertyUtils { if (method.getName().startsWith(IS_PREFIX) && !PsiType.BOOLEAN.equals(method.getReturnType())) { return false; } - if (method.getReturnType() == PsiType.VOID) return false; + if (PsiType.VOID.equals(method.getReturnType())) return false; if (propertyName == null) return true; final String byGetter = getPropertyNameByGetter(method); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index dff1ddc2ac6f..4f845706ec24 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -1182,7 +1182,7 @@ public class PsiUtil { if (controlFlowOwnerParent instanceof GrMethod && ((GrMethod)controlFlowOwnerParent).isConstructor()) { return false; } - else if (controlFlowOwnerParent instanceof PsiMethod && ((PsiMethod)controlFlowOwnerParent).getReturnType() == PsiType.VOID) { + else if (controlFlowOwnerParent instanceof PsiMethod && PsiType.VOID.equals(((PsiMethod)controlFlowOwnerParent).getReturnType())) { return false; } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java index f38b17bc9b83..68f7f8440945 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,7 +59,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatem import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; -import org.jetbrains.plugins.groovy.lang.psi.impl.GrTraitType; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; @@ -369,9 +368,6 @@ public class ResolveUtil { final PsiClass superClass = cls.getSuperClass(); key = cls.getName() + (superClass == null ? CommonClassNames.JAVA_LANG_OBJECT : superClass.getName()); } - else if (base instanceof GrTraitType) { - key = ((GrTraitType)base).erasure().getCanonicalText(); - } else if (base instanceof PsiClassType) { key = TypesUtil.getQualifiedName(base); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/AccessorResolverProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/AccessorResolverProcessor.java index 7dd187b9448e..2bc7e4a022ae 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/AccessorResolverProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/AccessorResolverProcessor.java @@ -97,7 +97,7 @@ public class AccessorResolverProcessor extends MethodResolverProcessor { } private static boolean isBoolean(PsiMethod method) { - return method.getReturnType() == PsiType.BOOLEAN; + return PsiType.BOOLEAN.equals(method.getReturnType()); } private boolean addAccessor(PsiMethod method, ResolveState state) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/GroovyStdTypeCalculators.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/GroovyStdTypeCalculators.java index 0bf7b50c36de..7097cf10bb1e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/GroovyStdTypeCalculators.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/GroovyStdTypeCalculators.java @@ -58,7 +58,7 @@ public class GroovyStdTypeCalculators { @Override public PsiType compute() { PsiType returnType = finalClosure.getReturnType(); - if (returnType == PsiType.VOID) return null; + if (PsiType.VOID.equals(returnType)) return null; return returnType; } }); diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 567c72430b0c..40b1b701a1ee 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -128,6 +128,8 @@ + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/hint/GroovyExpressionTypeProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/hint/GroovyExpressionTypeProvider.java index 8408b4d746ab..5726f707d1b7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/hint/GroovyExpressionTypeProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/hint/GroovyExpressionTypeProvider.java @@ -31,7 +31,7 @@ public class GroovyExpressionTypeProvider extends ExpressionTypeProvider" : type.getCanonicalText()); + return StringUtil.escapeXml(type == null ? "" : type.getPresentableText()); } @NotNull diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertSimpleGetterToPropertyIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertSimpleGetterToPropertyIntention.java index f88b809997a0..b0cdfbf1cc1f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertSimpleGetterToPropertyIntention.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertSimpleGetterToPropertyIntention.java @@ -96,7 +96,7 @@ public class ConvertSimpleGetterToPropertyIntention extends Intention { GrStatement statement = statements[0]; if (!(statement instanceof GrReturnStatement && ((GrReturnStatement)statement).getReturnValue() != null || - statement instanceof GrExpression && ((GrExpression)statement).getType() != PsiType.VOID)) { + statement instanceof GrExpression && !PsiType.VOID.equals(((GrExpression)statement).getType()))) { return false; } return true; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/declaration/GrIntroduceLocalVariableIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/declaration/GrIntroduceLocalVariableIntention.java index d4e3c2d8d1dd..98986caf43db 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/declaration/GrIntroduceLocalVariableIntention.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/declaration/GrIntroduceLocalVariableIntention.java @@ -48,7 +48,7 @@ public class GrIntroduceLocalVariableIntention extends Intention { private static boolean isTargetVisible(PsiElement element) { if (PsiUtil.isExpressionStatement(element) && element instanceof GrExpression) { - if (((GrExpression)element).getType() != PsiType.VOID) { + if (!PsiType.VOID.equals(((GrExpression)element).getType())) { if (PsiTreeUtil.getParentOfType(element, GrAssignmentExpression.class) == null) { return true; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/CompleteReferenceExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/CompleteReferenceExpression.java index cbd54abfbbbb..3878f65b556a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/CompleteReferenceExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/CompleteReferenceExpression.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -290,7 +290,7 @@ public class CompleteReferenceExpression { Project project = qualifier.getProject(); final PsiType qualifierType = TypesUtil.boxPrimitiveType(qualifier.getType(), qualifier.getManager(), qualifier.getResolveScope()); final ResolveState state = ResolveState.initial(); - if (qualifierType == null || qualifierType == PsiType.VOID) { + if (qualifierType == null || PsiType.VOID.equals(qualifierType)) { if (qualifier instanceof GrReferenceExpression) { PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); if (resolved instanceof PsiPackage || resolved instanceof PsiVariable) { @@ -300,24 +300,17 @@ public class CompleteReferenceExpression { } getVariantsFromQualifierType(TypesUtil.getJavaLangObject(qualifier), project); } + else if (qualifierType instanceof GrTraitType) { + PsiType[] conjuncts = ((GrTraitType)qualifierType).getConjuncts(); + for (int i = conjuncts.length - 1; i >= 0; i--) { + getVariantsFromQualifierType(conjuncts[i], project); + } + } else if (qualifierType instanceof PsiIntersectionType) { for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) { getVariantsFromQualifierType(conjunct, project); } } - else if (qualifierType instanceof GrTraitType) { - GrTypeDefinition definition = ((GrTraitType)qualifierType).getMockTypeDefinition(); - if (definition != null) { - PsiClassType classType = JavaPsiFacade.getElementFactory(project).createType(definition); - getVariantsFromQualifierType(classType, project); - } - else { - getVariantsFromQualifierType(((GrTraitType)qualifierType).getExprType(), project); - for (PsiClassType traitType : ((GrTraitType)qualifierType).getTraitTypes()) { - getVariantsFromQualifierType(traitType, project); - } - } - } else { getVariantsFromQualifierType(qualifierType, project); if (qualifier instanceof GrReferenceExpression && !PsiUtil.isSuperReference(qualifier) && !PsiUtil.isInstanceThisRef(qualifier)) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java index b2e476fe1151..103e78e0161e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java @@ -323,7 +323,7 @@ public class GroovyCompletionData { PsiElement parent = flowOwner.getParent(); if (parent instanceof GrMethod) { - return ((GrMethod)parent).getReturnType() != PsiType.VOID; + return !PsiType.VOID.equals(((GrMethod)parent).getReturnType()); } else if (parent instanceof GrClassInitializer) { return false; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java index 40b7ae0d1537..aabda2323527 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java @@ -325,7 +325,7 @@ public class GroovyCompletionUtil { private static boolean getterMatches(PrefixMatcher matcher, PsiMethod element, String importedName) { return GroovyPropertyUtils.isSimplePropertyGetter(element) && (matcher.prefixMatches(GroovyPropertyUtils.getGetterNameNonBoolean(importedName)) || - element.getReturnType() == PsiType.BOOLEAN && matcher.prefixMatches(GroovyPropertyUtils.getGetterNameBoolean(importedName))); + PsiType.BOOLEAN.equals(element.getReturnType()) && matcher.prefixMatches(GroovyPropertyUtils.getGetterNameBoolean(importedName))); } public static LookupElement createClassLookupItem(PsiClass psiClass) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/documentation/GroovyDocumentationProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/documentation/GroovyDocumentationProvider.java index be2e8315d780..1e0e21335cbb 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/documentation/GroovyDocumentationProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/documentation/GroovyDocumentationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -209,7 +209,7 @@ public class GroovyDocumentationProvider implements CodeDocumentationProvider, E if (inferredType != null) { buffer.append("[inferred type] "); - PsiImplUtil.appendTypeString(buffer, inferredType, originalElement); + appendTypeString(buffer, inferredType, originalElement); } else { buffer.append("[cannot infer type]"); @@ -263,11 +263,9 @@ public class GroovyDocumentationProvider implements CodeDocumentationProvider, E } private static void generateTraitType(@NotNull StringBuilder buffer, @NotNull GrTraitType type, PsiElement context) { - PsiClassType exprType = type.getExprType(); - List traitTypes = type.getTraitTypes(); - appendTypeString(buffer, exprType, context); + appendTypeString(buffer, type.getExprType(), context); buffer.append(" as "); - for (PsiClassType traitType : traitTypes) { + for (PsiType traitType : type.getTraitTypes()) { appendTypeString(buffer, traitType, context); buffer.append(", "); } @@ -496,8 +494,7 @@ public class GroovyDocumentationProvider implements CodeDocumentationProvider, E JavaDocumentationProvider.generateParametersTakingDocFromSuperMethods(project, builder, commenter, method); final PsiType returnType = method.getInferredReturnType(); - if ((returnType != null || method.getModifierList().hasModifierProperty(GrModifier.DEF)) && - returnType != PsiType.VOID) { + if ((returnType != null || method.getModifierList().hasModifierProperty(GrModifier.DEF)) && !PsiType.VOID.equals(returnType)) { builder.append(CodeDocumentationUtil.createDocCommentLine(RETURN_TAG, project, commenter)); builder.append(LINE_SEPARATOR); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java index 7e51e035f09f..904533c3f79c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java @@ -274,7 +274,7 @@ public class GroovyOverrideImplementUtil { @NotNull private static String callSuper(PsiMethod superMethod, PsiMethod overriding) { @NonNls StringBuilder buffer = new StringBuilder(); - if (!superMethod.isConstructor() && superMethod.getReturnType() != PsiType.VOID) { + if (!superMethod.isConstructor() && !PsiType.VOID.equals(superMethod.getReturnType())) { buffer.append("return "); } buffer.append("super"); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClassItemGeneratorImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClassItemGeneratorImpl.java index 7fb3308782a5..3a7c6508c3d7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClassItemGeneratorImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClassItemGeneratorImpl.java @@ -190,7 +190,7 @@ public class ClassItemGeneratorImpl implements ClassItemGenerator { builder.append("this"); } else { - if (context.typeProvider.getReturnType(method) != PsiType.VOID) { + if (!PsiType.VOID.equals(context.typeProvider.getReturnType(method))) { builder.append("return "); } builder.append(method.getName()); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java index 679deff5a1eb..221246b2e337 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java @@ -90,7 +90,7 @@ public class ClosureGenerator { final GrParameter[] parameters = block.getAllParameters(); GenerationUtil.writeParameterList(builder, parameters, new GeneratorClassNameProvider(), context); - Collection myExitPoints = returnType != PsiType.VOID ? ControlFlowUtils.collectReturns(block) : Collections.emptySet(); + Collection myExitPoints = !PsiType.VOID.equals(returnType) ? ControlFlowUtils.collectReturns(block) : Collections.emptySet(); boolean shouldInsertReturnNull = !(returnType instanceof PsiPrimitiveType) && MissingReturnInspection.methodMissesSomeReturns(block, MissingReturnInspection.ReturnStatus.shouldNotReturnValue); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java index 70581983a0b2..d367f3db936a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java @@ -101,7 +101,7 @@ public class CodeBlockGenerator extends Generator { boolean shouldInsertReturnNull; myExitPoints.clear(); PsiType returnType = context.typeProvider.getReturnType(method); - if (!method.isConstructor() && returnType != PsiType.VOID) { + if (!method.isConstructor() && !PsiType.VOID.equals(returnType)) { myExitPoints.addAll(ControlFlowUtils.collectReturns(block)); shouldInsertReturnNull = block != null && !(returnType instanceof PsiPrimitiveType) && @@ -338,7 +338,7 @@ public class CodeBlockGenerator extends Generator { private boolean isRealExpression(GrExpression expression) { final PsiType type = expression.getType(); - if (type == PsiType.VOID) return false; //statement + if (PsiType.VOID.equals(type)) return false; //statement if (type == PsiType.NULL) return !org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.isVoidMethodCall(expression); @@ -351,7 +351,8 @@ public class CodeBlockGenerator extends Generator { builder.append("return "); final PsiType expectedReturnType = PsiImplUtil.inferReturnType(expression); - final PsiType nnReturnType = expectedReturnType == null || expectedReturnType == PsiType.VOID ? TypesUtil.getJavaLangObject(expression) : expectedReturnType; + final PsiType nnReturnType = expectedReturnType == null || PsiType.VOID.equals(expectedReturnType) + ? TypesUtil.getJavaLangObject(expression) : expectedReturnType; GenerationUtil.wrapInCastIfNeeded(builder, nnReturnType, expression.getNominalType(), expression, context, new StatementWriter() { @Override public void writeStatement(StringBuilder builder, ExpressionContext context) { @@ -382,7 +383,7 @@ public class CodeBlockGenerator extends Generator { builder.append("if ("); if (condition != null) { final PsiType type = condition.getType(); - if (TypesUtil.unboxPrimitiveTypeWrapper(type) == PsiType.BOOLEAN) { + if (PsiType.BOOLEAN.equals(TypesUtil.unboxPrimitiveTypeWrapper(type))) { writeExpression(condition, builder, context); } else { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java index aceef3c34b84..5c2c3ba0c91a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java @@ -374,7 +374,7 @@ public class ExpressionGenerator extends Generator { var = null; } final PsiType type = condition.getType(); - if (type == null || TypesUtil.unboxPrimitiveTypeWrapper(type) == PsiType.BOOLEAN) { + if (type == null || PsiType.BOOLEAN.equals(TypesUtil.unboxPrimitiveTypeWrapper(type))) { if (elvis) { builder.append(var); } @@ -721,7 +721,7 @@ public class ExpressionGenerator extends Generator { } private static boolean isBooleanType(PsiType type) { - return type == PsiType.BOOLEAN || type != null && type.equalsToText(CommonClassNames.JAVA_LANG_BOOLEAN); + return PsiType.BOOLEAN.equals(type) || type != null && type.equalsToText(CommonClassNames.JAVA_LANG_BOOLEAN); } private void writeSimpleBinaryExpression(PsiElement opToken, GrExpression left, GrExpression right) { @@ -901,7 +901,7 @@ public class ExpressionGenerator extends Generator { boolean isChar = false; for (TypeConstraint constraint : constraints) { - if (constraint instanceof SubtypeConstraint && TypesUtil.unboxPrimitiveTypeWrapper(constraint.getDefaultType()) == PsiType.CHAR) { + if (constraint instanceof SubtypeConstraint && PsiType.CHAR.equals(TypesUtil.unboxPrimitiveTypeWrapper(constraint.getDefaultType()))) { isChar = true; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractUtil.java index e2ef05c0a2de..4c4515315eb8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractUtil.java @@ -46,12 +46,12 @@ import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner; import org.jetbrains.plugins.groovy.lang.psi.api.util.GrVariableDeclarationOwner; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo; import org.jetbrains.plugins.groovy.lang.psi.impl.ApplicationStatementUtil; +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyNamesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; -import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyNamesUtil; import org.jetbrains.plugins.groovy.refactoring.extract.method.ExtractMethodInfoHelper; import org.jetbrains.plugins.groovy.refactoring.introduce.StringPartInfo; @@ -323,7 +323,7 @@ public class ExtractUtil { buffer.append(") { \n"); GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(helper.getProject()); - generateBody(helper, type == PsiType.VOID, buffer, helper.isForceReturn()); + generateBody(helper, PsiType.VOID.equals(type), buffer, helper.isForceReturn()); buffer.append("\n}"); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.java index da9869133eed..60a41dae6c1c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.java @@ -144,7 +144,7 @@ public class GroovyExtractMethodDialog extends DialogWrapper { myNameLabel.setLabelFor(myNameField); final PsiType type = myHelper.getOutputType(); - if (type != PsiType.VOID) { + if (!PsiType.VOID.equals(type)) { myForceReturnCheckBox.setSelected(GroovyApplicationSettings.getInstance().FORCE_RETURN); } else { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyMethodInliner.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyMethodInliner.java index a38cf14cfe58..2d52b8e88e06 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyMethodInliner.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyMethodInliner.java @@ -257,7 +257,7 @@ public class GroovyMethodInliner implements InlineHandler.Inliner { } // Process method return statements - if (returnCount > 1 && PsiType.VOID != methodType && !isTailMethodCall) { + if (returnCount > 1 && !PsiType.VOID.equals(methodType) && !isTailMethodCall) { PsiType type = methodType != null && methodType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) ? null : methodType; GrVariableDeclaration resultDecl = factory.createVariableDeclaration(ArrayUtil.EMPTY_STRING_ARRAY, "", type, resultName); GrStatement statement = ((GrStatementOwner) owner).addStatementBefore(resultDecl, anchor); @@ -421,7 +421,7 @@ public class GroovyMethodInliner implements InlineHandler.Inliner { if (statements[0] instanceof GrExpression) return (GrExpression) statements[0]; if (statements[0] instanceof GrReturnStatement) { GrExpression value = ((GrReturnStatement) statements[0]).getReturnValue(); - if (value == null && PsiUtil.getSmartReturnType(method) != PsiType.VOID) { + if (value == null && !PsiType.VOID.equals(PsiUtil.getSmartReturnType(method))) { return GroovyPsiElementFactory.getInstance(method.getProject()).createExpressionFromText("null"); } return value; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java index bb1953bbca86..fd84b3c10ca9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java @@ -237,7 +237,7 @@ public abstract class GrIntroduceHandlerBaseo()' : 'T1', + '(new Foo() as T1).bar()' : 'T1', + '(new Foo() as T1).someMethod()' : 'Foo', + '(new Foo() as T1).fooMethod()' : 'Foo', + '((new Foo() as T1) as T2).foo()': 'T2', + '((new Foo() as T1) as T2).bar()': 'T1', + ]) + } + + void 'test `withTraits()`'() { + testResolveContainingClass([ + 'new Foo().withTraits(T1).foo()' : 'T1', + 'new Foo().withTraits(T1).bar()' : 'T1', + 'new Foo().withTraits(T1).withTraits(T2).foo()': 'T2', + 'new Foo().withTraits(T2).withTraits(T1).foo()': 'T1', + ]) + } + + void 'test duplicates and order'() { + testResolveContainingClass([ + '(new Foo() as T1).withTraits(T2, T1).foo()': 'T1' + ]) + } + + void 'test completion proirity'() { + fixture.configureByText GroovyFileType.GROOVY_FILE_TYPE, '''\ +(new Foo().withTraits(T1, T2).f) +''' + def method = fixture.findClass('T2').findMethodsByName('foo', false)[0] + def lookupElements = fixture.complete(CompletionType.BASIC) + assert lookupElements.find { it.psiElement == method } + } + + def T configureByExpression(String text, Class expressionType = GrExpression) { + assert text + fixture.configureByText GroovyFileType.GROOVY_FILE_TYPE, text + PsiTreeUtil.findFirstParent(fixture.file.findElementAt(0), { PsiElement element -> + element in expressionType && element.text == text + }).asType(expressionType) + } + + def testExpressionType(String expressionString, String typeString) { + configureByExpression(expressionString).with { GrExpression expression -> + assert expression.type: expression.getText() + assert expression.type.internalCanonicalText == typeString: "$expression.text: $expression.type.internalCanonicalText == $typeString" + } + } + + def testExpressionTypes(Map data) { + data.each this.&testExpressionType + } + + def testResolveContainingClass(Map data) { + data.each { k, v -> + assert resolveByText(k, GrMethod).containingClass == fixture.findClass(v) + } + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy index 4ab258e57d86..6ad716aead4a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy @@ -30,7 +30,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEn import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrBindingVariable -import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrTraitMethod import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil import org.jetbrains.plugins.groovy.util.TestUtils @@ -1476,7 +1475,7 @@ class B { def v = new B() as A print v.foo -''', GrTraitMethod) +''', GrAccessorMethod) } void testTraitPropertyFromAsOperator2() { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java index 5215ae2ae44c..f4e3b10f1dd4 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java @@ -351,7 +351,7 @@ public class MavenIndex { private void handleUpdateException(Exception e) { myFailureMessage = e.getMessage(); - MavenLog.LOG.warn("Failed to update Maven indices for: [" + myId + "] " + myRepositoryPathOrUrl, e); + MavenLog.LOG.warn("Failed to update Maven indices for: [" + myId.getValue() + "] " + myRepositoryPathOrUrl, e); } private int createContext(File contextDir, String suffix) throws MavenServerIndexerException { diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java index bd55bb31b4d7..ba658b2e27a3 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java @@ -371,7 +371,7 @@ public abstract class MavenImportingTestCase extends MavenTestCase { return getRootManager(moduleName).getContentEntries(); } - private ModuleRootManager getRootManager(String module) { + public ModuleRootManager getRootManager(String module) { return ModuleRootManager.getInstance(getModule(module)); } diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/actions/MavenProjectModelModifierTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/actions/MavenProjectModelModifierTest.java index 2822493cb873..e55fb286c73d 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/actions/MavenProjectModelModifierTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/actions/MavenProjectModelModifierTest.java @@ -17,9 +17,7 @@ package org.jetbrains.idea.maven.actions; import com.intellij.openapi.module.EffectiveLanguageLevelUtil; import com.intellij.openapi.module.Module; -import com.intellij.openapi.roots.DependencyScope; -import com.intellij.openapi.roots.ExternalLibraryDescriptor; -import com.intellij.openapi.roots.JavaProjectModelModifier; +import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; import com.intellij.openapi.vfs.VirtualFile; @@ -44,8 +42,8 @@ import java.util.regex.Pattern; public class MavenProjectModelModifierTest extends MavenDomWithIndicesTestCase { public void testAddExternalLibraryDependency() throws IOException { importProject("test" + - "project" + - "1"); + "project" + + "1"); Promise result = getExtension().addExternalLibraryDependency(Collections.singletonList(getModule("project")), new JunitLibraryDescriptor(), @@ -98,14 +96,21 @@ public class MavenProjectModelModifierTest extends MavenDomWithIndicesTestCase { "project" + "1"); - Promise result = - getExtension().addExternalLibraryDependency(Collections.singletonList(getModule("project")), new CommonsIoLibraryDescriptorUnknownVersion(), - DependencyScope.COMPILE); + Promise result = getExtension().addExternalLibraryDependency( + Collections.singletonList(getModule("project")), new CommonsIoLibraryDescriptorUnknownVersion(), DependencyScope.COMPILE); assertNotNull(result); final String version = assertHasDependency(myProjectPom, "commons-io", "commons-io"); assertEquals("RELEASE", version); waitUntilImported(result); - assertModuleLibDep("project", "Maven: commons-io:commons-io:2.4"); + + LibraryOrderEntry dep = null; + for (OrderEntry e : getRootManager("project").getOrderEntries()) { + // can be commons-io:commons-io:2.4 or commons-io:commons-io:RELEASE + if (LibraryOrderEntry.class.isInstance(e) && e.getPresentableName().startsWith("Maven: commons-io:commons-io:")) { + dep = (LibraryOrderEntry)e; + } + } + assertNotNull(dep); } public void testAddModuleDependency() throws IOException { diff --git a/plugins/testng/src/resources/standardSchemas/testng-1.0.dtd b/plugins/testng/src/resources/standardSchemas/testng-1.0.dtd index c1a478ab1c6f..8c7da51f678e 100644 --- a/plugins/testng/src/resources/standardSchemas/testng-1.0.dtd +++ b/plugins/testng/src/resources/standardSchemas/testng-1.0.dtd @@ -30,16 +30,19 @@ Cedric Beust & Alexandru Popescu - + + group-by-instances (true | false) "false" + preserve-order (true | false) "true" + allow-return-values (true | false) "false" + > @@ -75,7 +84,7 @@ Cedric Beust & Alexandru Popescu + > + preserve-order (true | false) "true" + group-by-instances (true | false) "false" + allow-return-values (true | false) "false" + > - + - + + + + + + - + @@ -180,7 +201,7 @@ Defines additional groups ("groups of groups") and also which groups to include name CDATA #REQUIRED > - + diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/Generator.java b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/Generator.java index 771a10dec6e9..2c2bd87b0b6e 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/Generator.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/Generator.java @@ -25,7 +25,6 @@ import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; @@ -587,7 +586,7 @@ public final class Generator { outer: for (int i = 0; i < allGetDataMethods.length; i++) { final PsiMethod _getMethod = allGetDataMethods[i]; - if (_getMethod.getReturnType() != PsiType.VOID) { + if (!PsiType.VOID.equals(_getMethod.getReturnType())) { continue; } @@ -602,7 +601,7 @@ public final class Generator { } for (final PsiMethod _setMethod : allSetDataMethods) { - if (_setMethod.getReturnType() != PsiType.VOID) { + if (!PsiType.VOID.equals(_setMethod.getReturnType())) { continue; } diff --git a/python/edu/course-creator-python/resources/META-INF/plugin.xml b/python/edu/course-creator-python/resources/META-INF/plugin.xml index 1aae572b65b5..96bd6f624ede 100644 --- a/python/edu/course-creator-python/resources/META-INF/plugin.xml +++ b/python/edu/course-creator-python/resources/META-INF/plugin.xml @@ -2,7 +2,7 @@ com.jetbrains.edu.coursecreator.python Course Creator for PyCharm Edu 2.0 - + . ]]> @@ -22,6 +22,8 @@ com.intellij.modules.platform com.intellij.modules.python com.jetbrains.edu.coursecreator + com.jetbrains.edu.core + com.jetbrains.python.edu.core diff --git a/python/edu/interactive-learning-python/resources/META-INF/plugin.xml b/python/edu/interactive-learning-python/resources/META-INF/plugin.xml index e5f7e473282d..1adcccf71a9c 100644 --- a/python/edu/interactive-learning-python/resources/META-INF/plugin.xml +++ b/python/edu/interactive-learning-python/resources/META-INF/plugin.xml @@ -18,6 +18,8 @@ com.intellij.modules.lang com.intellij.modules.python com.jetbrains.edu.interactivelearning + com.jetbrains.edu.core + com.jetbrains.python.edu.core diff --git a/python/edu/resources/META-INF/plugin.xml b/python/edu/resources/META-INF/plugin.xml new file mode 100644 index 000000000000..995178645571 --- /dev/null +++ b/python/edu/resources/META-INF/plugin.xml @@ -0,0 +1,33 @@ + + com.jetbrains.python.edu.core + Python-specific part for Stepic connector + 2.0 + + + JetBrains + + + + + + + com.intellij.modules.lang + + + + + + + + + + + + + + \ No newline at end of file diff --git a/python/educational/course-creator/resources/META-INF/plugin.xml b/python/educational/course-creator/resources/META-INF/plugin.xml index 672d7c6f3ed7..d553a3ae30b6 100644 --- a/python/educational/course-creator/resources/META-INF/plugin.xml +++ b/python/educational/course-creator/resources/META-INF/plugin.xml @@ -2,7 +2,7 @@ com.jetbrains.edu.coursecreator Course Creator Plugin 2.0 - + @@ -19,6 +19,7 @@ com.intellij.modules.lang --> com.intellij.modules.platform + com.jetbrains.edu.core diff --git a/python/educational/interactive-learning/resources/META-INF/plugin.xml b/python/educational/interactive-learning/resources/META-INF/plugin.xml index 4610eb466f89..35d4322c1a32 100644 --- a/python/educational/interactive-learning/resources/META-INF/plugin.xml +++ b/python/educational/interactive-learning/resources/META-INF/plugin.xml @@ -20,6 +20,7 @@ on how to target different products --> com.intellij.modules.lang + com.jetbrains.edu.core diff --git a/python/educational/resources/META-INF/plugin.xml b/python/educational/resources/META-INF/plugin.xml new file mode 100644 index 000000000000..3a5a7bb1b1dc --- /dev/null +++ b/python/educational/resources/META-INF/plugin.xml @@ -0,0 +1,33 @@ + + com.jetbrains.edu.core + Stepic connector + 2.0 + + + JetBrains + + + + + + + com.intellij.modules.lang + + + + + + + + + + + + + + \ No newline at end of file diff --git a/python/helpers/rest_formatter.py b/python/helpers/rest_formatter.py index 03fffd93848f..45755976750b 100644 --- a/python/helpers/rest_formatter.py +++ b/python/helpers/rest_formatter.py @@ -133,19 +133,19 @@ class RestHTMLTranslator(_EpydocHTMLTranslator): fields["return"] = n for n in node.children: - if not n.children: + if len(n.children) < 2: continue - child = n.children[0] - rawsource = child.rawsource + field_name, field_body = n.children[0], n.children[1] + rawsource = field_name.rawsource if rawsource.startswith("type "): index = rawsource.index("type ") name = re.sub(r'\\\*', '*', rawsource[index + 5:]) if name in fields: - fields[name].type = n.children[1][0][0] + fields[name].type = field_body[0][0] if field_body.children else '' node.children.remove(n) if rawsource == "rtype": if "return" in fields: - fields["return"].type = n.children[1][0][0] + fields["return"].type = field_body[0][0] if field_body.children else '' node.children.remove(n) HTMLTranslator.visit_field_list(self, node) diff --git a/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMember.java b/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMember.java index 77218c6457fc..543d635050d5 100644 --- a/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMember.java +++ b/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMember.java @@ -17,8 +17,11 @@ package com.jetbrains.python.codeInsight; import com.intellij.extapi.psi.ASTWrapperPsiElement; import com.intellij.icons.AllIcons; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; +import com.intellij.psi.util.*; import com.intellij.util.Function; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; @@ -34,7 +37,9 @@ import javax.swing.*; /** * @author Dennis.Ushakov */ -public class PyCustomMember { +public class PyCustomMember extends UserDataHolderBase { + private static final Key> + RESOLVE = Key.create("resolve"); private final String myName; private final boolean myResolveToInstance; private final Function myTypeCallback; @@ -165,14 +170,26 @@ public class PyCustomMember { } @Nullable - public PsiElement resolve(@NotNull PsiElement context) { + public PsiElement resolve(@NotNull final PsiElement context) { + if (myTarget != null) { return myTarget; } PyClass targetClass = null; if (myTypeName != null) { - targetClass = PyPsiFacade.getInstance(context.getProject()).createClassByQName(myTypeName, context); + + final ParameterizedCachedValueProvider provider = new ParameterizedCachedValueProvider() { + @Nullable + @Override + public CachedValueProvider.Result compute( + final PsiElement param) { + final PyClass result = PyPsiFacade.getInstance(param.getProject()).createClassByQName(myTypeName, param); + return CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT); + } + }; + targetClass = CachedValuesManager.getManager(context.getProject()).getParameterizedCachedValue(this, RESOLVE, + provider, false, context); } final PsiElement resolveTarget = findResolveTarget(context); if (resolveTarget instanceof PyFunction && !myAlwaysResolveToCustomElement) { @@ -212,6 +229,7 @@ public class PyCustomMember { /** * Checks if some reference points to this element + * * @param reference reference to check * @return true if reference points to it */ diff --git a/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java b/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java index b9cbbaec5061..86d52efc483a 100644 --- a/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java +++ b/python/psi-api/src/com/jetbrains/python/nameResolver/NameResolverTools.java @@ -18,19 +18,22 @@ package com.jetbrains.python.nameResolver; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiCacheKey; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.QualifiedName; import com.intellij.util.Function; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; +import com.jetbrains.python.psi.types.PyFunctionType; +import com.jetbrains.python.psi.types.PyType; +import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import java.util.*; /** * @author Ilya.Kazakevich @@ -64,7 +67,8 @@ public final class NameResolverTools { } /** - * Checks if FQ element name is one of provided names + * Checks if FQ element name is one of provided names. May be heavy. + * It is always better to use less accurate but lighter {@link #isCalleeShortCut(PyCallExpression, FQNamesProvider, TypeEvalContext)} * * @param element element to check * @param namesProviders some enum that has one or more names @@ -103,6 +107,74 @@ public final class NameResolverTools { return null; } + /** + * Same as {@link #isName(PyElement, FQNamesProvider...)} for call expr, but first checks name. + * Aliases not supported, but much lighter that way + * + * @param call expr + * @param function names to check + * @param context + * @return true if callee is correct + */ + public static boolean isCalleeShortCut(@NotNull final PyCallExpression call, + @NotNull final FQNamesProvider function, + @NotNull final TypeEvalContext context) { + final PyExpression callee = call.getCallee(); + if (callee == null) { + return false; + } + + final PyType calleeType = context.getType(callee); + if (!(calleeType instanceof PyFunctionType)) { + return false; + } + final PyCallable callable = ((PyFunctionType)calleeType).getCallable(); + final String callableName = callable.getName(); + if (callableName == null) { + return false; + } + + final Set possibleNames = new HashSet(); + for (final String lastComponent : getLastComponents(function)) { + possibleNames.add(lastComponent); + } + return possibleNames.contains(callableName) && call.isCallee(function); + } + + @NotNull + private static List getLastComponents(@NotNull final FQNamesProvider provider) { + final List result = new ArrayList(); + for (final String name : provider.getNames()) { + final String component = QualifiedName.fromDottedString(name).getLastComponent(); + if (component != null) { + result.add(component); + } + } + return result; + } + + /** + * Checks if some string contains last component one of name + * @param text test to check + * @param names + */ + public static boolean isContainsName(@NotNull final String text, @NotNull final FQNamesProvider names) { + for (final String lastComponent : getLastComponents(names)) { + if (text.contains(lastComponent)) { + return true; + } + } + return false; + } + /** + * Checks if some file contains last component one of name + * @param file file to check + * @param names + */ + public static boolean isContainsName(@NotNull final PsiFile file, @NotNull final FQNamesProvider names) { + return isContainsName(file.getText(), names); + } + /** * Looks for call of some function */ diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java index da96e7e29b61..4c5b6a1bd0f7 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyCallExpression.java @@ -19,6 +19,7 @@ import com.intellij.psi.PsiElement; import com.jetbrains.python.FunctionParameter; import com.jetbrains.python.nameResolver.FQNamesProvider; import com.jetbrains.python.psi.resolve.PyResolveContext; +import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -74,7 +75,7 @@ public interface PyCallExpression extends PyCallSiteExpression { * Returns the argument if one is present in the list. * * @param parameter parameter - * @param argClass argument expected type + * @param argClass argument expected type * @return the argument or null */ @Nullable @@ -85,6 +86,7 @@ public interface PyCallExpression extends PyCallSiteExpression { /** * TODO: Copy/Paste with {@link PyArgumentList#addArgument(PyExpression)} + * * @param expression */ void addArgument(PyExpression expression); @@ -110,7 +112,6 @@ public interface PyCallExpression extends PyCallSiteExpression { PyCallable resolveCalleeFunction(PyResolveContext resolveContext); /** - * * @param resolveContext the reference resolve context * @param implicitOffset known from the context implicit offset */ @@ -133,9 +134,13 @@ public interface PyCallExpression extends PyCallSiteExpression { /** * Checks if the qualified name of the callee matches any of the specified names provided by provider. - * @see com.jetbrains.python.nameResolver + * May be heavy. + * Use {@link com.jetbrains.python.nameResolver.NameResolverTools#isCalleeShortCut(PyCallExpression, FQNamesProvider, TypeEvalContext)} + * if you can. + * * @param name providers that provides one or more names to check * @return true if matches, false otherwise + * @see com.jetbrains.python.nameResolver */ boolean isCallee(@NotNull FQNamesProvider... name); @@ -243,8 +248,8 @@ public interface PyCallExpression extends PyCallSiteExpression { /** * @return number of implicitly passed positional parameters; 0 means no parameters are passed implicitly. - * Note that a *args is never marked as passed implicitly. - * E.g. for a function like foo(a, b, *args) always holds getImplicitOffset() < 2. + * Note that a *args is never marked as passed implicitly. + * E.g. for a function like foo(a, b, *args) always holds getImplicitOffset() < 2. */ public int getImplicitOffset() { return myImplicitOffset; diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java index 40407d6edac2..98c7be60a0d2 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java @@ -98,15 +98,14 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine PyExpression[] getSuperClassExpressions(); /** - * Collects methods defined in the class and its ancestors if necessary. + * Collects methods defined in the class. *

- * This method does not access AST if underlying PSI is stub based and {@code inherited} parameter is false. + * This method does not access AST if underlying PSI is stub based. * - * @param inherited return inherited (parent) methods as well * @return class methods */ @NotNull - PyFunction[] getMethods(boolean inherited); + PyFunction[] getMethods(); /** * Get class properties. diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyStatementListContainer.java b/python/psi-api/src/com/jetbrains/python/psi/PyStatementListContainer.java index c56b799f429c..b69e2c70f41e 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyStatementListContainer.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyStatementListContainer.java @@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull; /** * @author Ilya.Kazakevich */ -public interface PyStatementListContainer { +public interface PyStatementListContainer extends PyElement { @NotNull PyStatementList getStatementList(); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyStatementPart.java b/python/psi-api/src/com/jetbrains/python/psi/PyStatementPart.java index 0ebc50865504..b639f206277b 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyStatementPart.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyStatementPart.java @@ -20,6 +20,6 @@ package com.jetbrains.python.psi; * User: dcheryasov * Date: Mar 16, 2009 4:34:59 AM */ -public interface PyStatementPart extends PyElement, PyStatementListContainer { +public interface PyStatementPart extends PyStatementListContainer { PyStatementPart[] EMPTY_ARRAY = new PyStatementPart[0]; } diff --git a/python/src/com/jetbrains/python/codeInsight/PyMethodNavigationOffsetProvider.java b/python/src/com/jetbrains/python/codeInsight/PyMethodNavigationOffsetProvider.java index 36c4faceaeff..438b79580f69 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyMethodNavigationOffsetProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/PyMethodNavigationOffsetProvider.java @@ -54,7 +54,7 @@ public class PyMethodNavigationOffsetProvider implements MethodNavigationOffsetP array.add(psiElement); } else if (psiElement instanceof PyClass) { - Collections.addAll(array, ((PyClass)psiElement).getMethods(false)); + Collections.addAll(array, ((PyClass)psiElement).getMethods()); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PySuperMethodCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PySuperMethodCompletionContributor.java index 24af1dfacd99..f182fc83da58 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PySuperMethodCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PySuperMethodCompletionContributor.java @@ -57,13 +57,13 @@ public class PySuperMethodCompletionContributor extends CompletionContributor { return; } Set seenNames = new HashSet(); - for (PyFunction function : containingClass.getMethods(false)) { + for (PyFunction function : containingClass.getMethods()) { seenNames.add(function.getName()); } LanguageLevel languageLevel = LanguageLevel.forElement(parameters.getOriginalFile()); seenNames.addAll(PyNames.getBuiltinMethods(languageLevel).keySet()); for (PyClass ancestor : containingClass.getAncestorClasses(null)) { - for (PyFunction superMethod : ancestor.getMethods(false)) { + for (PyFunction superMethod : ancestor.getMethods()) { if (!seenNames.contains(superMethod.getName())) { String text = superMethod.getName() + superMethod.getParameterList().getText(); LookupElementBuilder element = LookupElementBuilder.create(text); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInPy3AnnotationsIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInPy3AnnotationsIntention.java index c6f13a67839f..dd3f1aae4f75 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInPy3AnnotationsIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInPy3AnnotationsIntention.java @@ -17,19 +17,23 @@ package com.jetbrains.python.codeInsight.intentions; import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.codeInsight.template.*; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; +import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.impl.PyPsiUtils; import org.jetbrains.annotations.NotNull; /** @@ -68,7 +72,7 @@ public class SpecifyTypeInPy3AnnotationsIntention extends TypeIntention { annotateParameter(project, editor, parameter); } else { - annotateReturnType(project, elementAt); + annotateReturnType(project, editor.getDocument(), elementAt); } } @@ -99,24 +103,32 @@ public class SpecifyTypeInPy3AnnotationsIntention extends TypeIntention { } } - private void annotateReturnType(Project project, PsiElement resolved) { - final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project); - + private void annotateReturnType(Project project, Document document, PsiElement resolved) { PyCallable callable = getCallable(resolved); if (callable instanceof PyFunction) { - final String functionSignature = "def " + callable.getName() + callable.getParameterList().getText(); - String functionText = functionSignature + - " -> object:"; - final PyStatementList statementList = ((PyFunction)callable).getStatementList(); - for (PyStatement st : statementList.getStatements()) { - functionText = functionText + "\n\t" + st.getText(); - } - final PyFunction function = elementGenerator.createFromText(LanguageLevel.forElement(callable), PyFunction.class, - functionText); - callable = (PyFunction)callable.replace(function); - callable = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(callable); + final String annotationText = " -> " + PyNames.OBJECT; + + final PsiElement prevElem = PyPsiUtils.getPrevNonCommentSibling(((PyFunction)callable).getStatementList(), true); + assert prevElem != null; + final PsiDocumentManager manager = PsiDocumentManager.getInstance(project); + try { + final TextRange range = prevElem.getTextRange(); + manager.doPostponedOperationsAndUnblockDocument(document); + if (prevElem.getNode().getElementType() == PyTokenTypes.COLON) { + document.insertString(range.getStartOffset(), annotationText); + } + else { + document.insertString(range.getEndOffset(), annotationText + ":"); + } + } + finally { + manager.commitDocument(document); + } + + + callable = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(callable); final PyAnnotation annotation = ((PyFunction)callable).getAnnotation(); assert annotation != null; final PyExpression annotationValue = annotation.getValue(); diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java index 042e115896c4..8b7e1d9a3599 100644 --- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java @@ -16,6 +16,7 @@ package com.jetbrains.python.codeInsight.override; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.featureStatistics.ProductivityFeatureNames; @@ -41,8 +42,8 @@ import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyFunctionBuilder; import com.jetbrains.python.psi.impl.PyPsiUtils; import com.jetbrains.python.psi.types.PyClassLikeType; -import com.jetbrains.python.psi.types.PyTypeUtil; import com.jetbrains.python.psi.types.PyNoneType; +import com.jetbrains.python.psi.types.PyTypeUtil; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -316,25 +317,22 @@ public class PyOverrideImplementUtil { return toClass.getName(); } + /** + * Returns all super functions available through MRO. + */ @NotNull - public static Collection getAllSuperFunctions(@NotNull PyClass pyClass, @NotNull TypeEvalContext context) { - - // This is a legacy approach. Should be removed soon since type-based members should be enough - final Map superFunctions = new HashMap(); - for (PyFunction function : pyClass.getMethods(true)) { - if (!superFunctions.containsKey(function.getName())) { - superFunctions.put(function.getName(), function); + public static List getAllSuperFunctions(@NotNull PyClass pyClass, @NotNull TypeEvalContext context) { + final Map functions = Maps.newLinkedHashMap(); + for (final PyClassLikeType type : pyClass.getAncestorTypes(context)) { + if (type != null) { + for (PyFunction function : PyTypeUtil.getMembersOfType(type, PyFunction.class, false, context)) { + final String name = function.getName(); + if (name != null && !functions.containsKey(name)) { + functions.put(name, function); + } + } } } - - - - final Set functions = new HashSet(superFunctions.values()); - final PyClassLikeType type = PyUtil.as(context.getType(pyClass), PyClassLikeType.class); - - if (type != null) { - functions.addAll(PyTypeUtil.getMembersOfType(type, PyFunction.class, context)); - } - return functions; + return Lists.newArrayList(functions.values()); } } diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsClassMembersProvider.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsClassMembersProvider.java index c7512d3f11b5..387aa2f81307 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsClassMembersProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsClassMembersProvider.java @@ -83,7 +83,7 @@ public class PyUserSkeletonsClassMembersProvider extends PyClassMembersProviderB public static Collection getClassMembers(@NotNull PyClass cls, boolean isDefinition) { final List result = new ArrayList(); - for (PyFunction function : cls.getMethods(false)) { + for (PyFunction function : cls.getMethods()) { final String name = function.getName(); final PyUtil.MethodFlags methodFlags = PyUtil.MethodFlags.of(function); final boolean instanceMethod = methodFlags == null || methodFlags.isInstanceMethod(); diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java index cd61ba75ee97..4cebb5b3e92c 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java @@ -134,7 +134,7 @@ public class PyDocumentationBuilder { final FileReader reader = new FileReader(PythonHelpersLocator.getHelperPath("/tools/python_keywords/" + name)); try { final String text = FileUtil.loadTextAndClose(reader); - myEpilog.addItem(text); + myEpilog.addItem(StringUtil.convertLineSeparators(text, "\n")); } catch (IOException ignored) { } diff --git a/python/src/com/jetbrains/python/documentation/docstrings/PyStructuredDocstringFormatter.java b/python/src/com/jetbrains/python/documentation/docstrings/PyStructuredDocstringFormatter.java index 975b936904f0..645dbe9aee03 100644 --- a/python/src/com/jetbrains/python/documentation/docstrings/PyStructuredDocstringFormatter.java +++ b/python/src/com/jetbrains/python/documentation/docstrings/PyStructuredDocstringFormatter.java @@ -71,20 +71,20 @@ public class PyStructuredDocstringFormatter { final DocStringFormat format = DocStringUtil.guessDocStringFormat(preparedDocstring, element); if (format == DocStringFormat.GOOGLE) { formatter = PythonHelper.GOOGLE_FORMATTER; - structuredDocString = DocStringUtil.parseDocString(DocStringFormat.GOOGLE, preparedDocstring); + structuredDocString = DocStringUtil.parseDocStringContent(DocStringFormat.GOOGLE, preparedDocstring); } else if (format == DocStringFormat.NUMPY) { formatter = PythonHelper.NUMPY_FORMATTER; - structuredDocString = DocStringUtil.parseDocString(DocStringFormat.NUMPY, preparedDocstring); + structuredDocString = DocStringUtil.parseDocStringContent(DocStringFormat.NUMPY, preparedDocstring); } else if (format == DocStringFormat.EPYTEXT) { formatter = PythonHelper.EPYDOC_FORMATTER; - structuredDocString = DocStringUtil.parseDocString(DocStringFormat.EPYTEXT, preparedDocstring); + structuredDocString = DocStringUtil.parseDocStringContent(DocStringFormat.EPYTEXT, preparedDocstring); result.add(formatStructuredDocString(structuredDocString)); } else if (format == DocStringFormat.REST) { formatter = PythonHelper.REST_FORMATTER; - structuredDocString = DocStringUtil.parseDocString(DocStringFormat.REST, preparedDocstring); + structuredDocString = DocStringUtil.parseDocStringContent(DocStringFormat.REST, preparedDocstring); } else { diff --git a/python/src/com/jetbrains/python/formatter/PyBlock.java b/python/src/com/jetbrains/python/formatter/PyBlock.java index dc45bed51317..9269c742eff3 100644 --- a/python/src/com/jetbrains/python/formatter/PyBlock.java +++ b/python/src/com/jetbrains/python/formatter/PyBlock.java @@ -77,7 +77,6 @@ public class PyBlock implements ASTBlock { PyElementTypes.CALL_EXPRESSION, PyElementTypes.FROM_IMPORT_STATEMENT); - private static final boolean DUMP_FORMATTING_BLOCKS = false; public static final Key IMPORT_GROUP_BEGIN = Key.create("com.jetbrains.python.formatter.importGroupBegin"); private final PyBlock myParent; @@ -93,12 +92,12 @@ public class PyBlock implements ASTBlock { private final Wrap myDictWrapping; private final boolean myEmptySequence; - public PyBlock(final PyBlock parent, - final ASTNode node, - final Alignment alignment, - final Indent indent, - final Wrap wrap, - final PyBlockContext context) { + public PyBlock(@Nullable PyBlock parent, + @NotNull ASTNode node, + @Nullable Alignment alignment, + @NotNull Indent indent, + @Nullable Wrap wrap, + @NotNull PyBlockContext context) { myParent = parent; myAlignment = alignment; myIndent = indent; @@ -117,11 +116,13 @@ public class PyBlock implements ASTBlock { } } + @Override @NotNull public ASTNode getNode() { return myNode; } + @Override @NotNull public TextRange getTextRange() { return myNode.getTextRange(); @@ -134,14 +135,12 @@ public class PyBlock implements ASTBlock { return myChildAlignment; } + @Override @NotNull public List getSubBlocks() { if (mySubBlocks == null) { mySubBlockByNode = buildSubBlocks(); mySubBlocks = new ArrayList(mySubBlockByNode.values()); - if (DUMP_FORMATTING_BLOCKS) { - dumpSubBlocks(); - } } return Collections.unmodifiableList(mySubBlocks); } @@ -174,7 +173,8 @@ public class PyBlock implements ASTBlock { return Collections.unmodifiableMap(blocks); } - private PyBlock buildSubBlock(ASTNode child) { + @NotNull + private PyBlock buildSubBlock(@NotNull ASTNode child) { final IElementType parentType = myNode.getElementType(); final ASTNode grandParentNode = myNode.getTreeParent(); @@ -248,7 +248,7 @@ public class PyBlock implements ASTBlock { } } - PyCodeStyleSettings settings = CodeStyleSettingsManager.getSettings(child.getPsi().getProject()).getCustomSettings(PyCodeStyleSettings.class); + final PyCodeStyleSettings settings = CodeStyleSettingsManager.getSettings(child.getPsi().getProject()).getCustomSettings(PyCodeStyleSettings.class); if (parentType == PyElementTypes.LIST_LITERAL_EXPRESSION || parentType == PyElementTypes.LIST_COMP_EXPRESSION) { if (childType == PyTokenTypes.RBRACKET || childType == PyTokenTypes.LBRACKET) { childIndent = Indent.getNoneIndent(); @@ -323,13 +323,8 @@ public class PyBlock implements ASTBlock { if (childType == PyTokenTypes.RPAR) { childIndent = Indent.getNoneIndent(); } - else { - if (parentType == PyElementTypes.PARAMETER_LIST || argumentMayHaveSameIndentAsFollowingStatementList()) { - childIndent = Indent.getContinuationIndent(); - } - else { - childIndent = Indent.getNormalIndent(); - } + else if (childType != PyTokenTypes.LPAR){ + childIndent = Indent.getContinuationIndent(); } } else if (parentType == PyElementTypes.SUBSCRIPTION_EXPRESSION) { @@ -426,16 +421,6 @@ public class PyBlock implements ASTBlock { return node.getPsi() instanceof PySequenceExpression && ((PySequenceExpression)node.getPsi()).isEmpty(); } - private boolean argumentMayHaveSameIndentAsFollowingStatementList() { - // This check is supposed to prevent PEP8's error: Continuation line with the same indent as next logical line - final PsiElement header = getControlStatementHeader(myNode); - if (header instanceof PyStatementListContainer) { - final PyStatementList statementList = ((PyStatementListContainer)header).getStatementList(); - return PyUtil.onSameLine(header, myNode.getPsi()) && !PyUtil.onSameLine(header, statementList); - } - return false; - } - // Check https://www.python.org/dev/peps/pep-0008/#indentation private static boolean hasHangingIndent(@NotNull PsiElement elem) { if (elem instanceof PyCallExpression) { @@ -518,7 +503,7 @@ public class PyBlock implements ASTBlock { return type != PyElementTypes.BINARY_EXPRESSION; } - private static Alignment getAlignmentOfChild(PyBlock b, int childNum) { + private static Alignment getAlignmentOfChild(@NotNull PyBlock b, int childNum) { if (b.getSubBlocks().size() > childNum) { final ChildAttributes attributes = b.getChildAttributes(childNum); return attributes.getAlignment(); @@ -526,7 +511,7 @@ public class PyBlock implements ASTBlock { return null; } - private static boolean isIndentNext(ASTNode child) { + private static boolean isIndentNext(@NotNull ASTNode child) { final PsiElement psi = PsiTreeUtil.getParentOfType(child.getPsi(), PyStatement.class); return psi instanceof PyIfStatement || @@ -540,7 +525,7 @@ public class PyBlock implements ASTBlock { psi instanceof PyWhileStatement; } - private static boolean isSubscriptionOperand(ASTNode child) { + private static boolean isSubscriptionOperand(@NotNull ASTNode child) { return child.getTreeParent().getElementType() == PyElementTypes.SUBSCRIPTION_EXPRESSION && child.getPsi() == ((PySubscriptionExpression)child.getTreeParent().getPsi()).getOperand(); } @@ -562,7 +547,7 @@ public class PyBlock implements ASTBlock { return null; } - private boolean isSliceOperand(ASTNode child) { + private boolean isSliceOperand(@NotNull ASTNode child) { if (myNode.getPsi() instanceof PySliceExpression) { final PySliceExpression sliceExpression = (PySliceExpression)myNode.getPsi(); final PyExpression operand = sliceExpression.getOperand(); @@ -571,7 +556,7 @@ public class PyBlock implements ASTBlock { return false; } - private static boolean isAfterStatementList(ASTNode child) { + private static boolean isAfterStatementList(@NotNull ASTNode child) { final PsiElement prev = child.getPsi().getPrevSibling(); if (!(prev instanceof PyStatement)) { return false; @@ -580,7 +565,7 @@ public class PyBlock implements ASTBlock { return lastChild.getParent() instanceof PyStatementList; } - private boolean needListAlignment(ASTNode child) { + private boolean needListAlignment(@NotNull ASTNode child) { final IElementType childType = child.getElementType(); if (PyTokenTypes.OPEN_BRACES.contains(childType)) { return false; @@ -616,7 +601,7 @@ public class PyBlock implements ASTBlock { } @Nullable - private static ASTNode findPrevNonSpaceNode(ASTNode node) { + private static ASTNode findPrevNonSpaceNode(@NotNull ASTNode node) { do { node = node.getTreePrev(); } @@ -671,37 +656,28 @@ public class PyBlock implements ASTBlock { return false; } - private void dumpSubBlocks() { - System.out.println("Subblocks of " + myNode.getPsi() + ":"); - for (Block block : mySubBlocks) { - if (block instanceof PyBlock) { - System.out.println(" " + ((PyBlock)block).getNode().getPsi().toString() + " " + block.getTextRange().getStartOffset() + ":" + block - .getTextRange().getLength()); - } - else { - System.out.println(" "); - } - } - } - + @Override @Nullable public Wrap getWrap() { return myWrap; } + @Override @Nullable public Indent getIndent() { assert myIndent != null; return myIndent; } + @Override @Nullable public Alignment getAlignment() { return myAlignment; } + @Override @Nullable - public Spacing getSpacing(Block child1, @NotNull Block child2) { + public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) { if (child1 instanceof ASTBlock && child2 instanceof ASTBlock) { final ASTNode node1 = ((ASTBlock)child1).getNode(); ASTNode node2 = ((ASTBlock)child2).getNode(); @@ -764,7 +740,8 @@ public class PyBlock implements ASTBlock { return myContext.getSpacingBuilder().getSpacing(this, child1, child2); } - private Spacing getBlankLinesForOption(final int option) { + @NotNull + private Spacing getBlankLinesForOption(int option) { final int blankLines = option + 1; return Spacing.createSpacing(0, 0, blankLines, myContext.getSettings().KEEP_LINE_BREAKS, @@ -781,6 +758,7 @@ public class PyBlock implements ASTBlock { return false; } + @Override @NotNull public ChildAttributes getChildAttributes(int newChildIndex) { int statementListsBelow = 0; @@ -812,8 +790,8 @@ public class PyBlock implements ASTBlock { // but I don't quite understand why it is necessary and why the formatter // doesn't request childAttributes from the correct block while (lastChild != null) { - final IElementType last_type = lastChild.getElementType(); - if (last_type == PyElementTypes.STATEMENT_LIST && hasLineBreaksBeforeInSameParent(lastChild, 1)) { + final IElementType lastType = lastChild.getElementType(); + if (lastType == PyElementTypes.STATEMENT_LIST && hasLineBreaksBeforeInSameParent(lastChild, 1)) { if (dedentAfterLastStatement((PyStatementList)lastChild.getPsi())) { break; } @@ -856,7 +834,7 @@ public class PyBlock implements ASTBlock { return new ChildAttributes(childIndent, childAlignment); } - private static boolean dedentAfterLastStatement(PyStatementList statementList) { + private static boolean dedentAfterLastStatement(@NotNull PyStatementList statementList) { final PyStatement[] statements = statementList.getStatements(); if (statements.length == 0) { return false; @@ -885,6 +863,7 @@ public class PyBlock implements ASTBlock { return null; } + @NotNull private Indent getChildIndent(int newChildIndex) { final ASTNode afterNode = getAfterNode(newChildIndex); final ASTNode lastChild = getLastNonSpaceChild(myNode, false); @@ -930,12 +909,12 @@ public class PyBlock implements ASTBlock { final PsiDocumentManager docMgr = PsiDocumentManager.getInstance(exprItem.getProject()); final Document doc = docMgr.getDocument(exprItem.getContainingFile()); if (doc != null) { - int line_num = doc.getLineNumber(exprItem.getTextOffset()); - final int item_col = exprItem.getTextOffset() - doc.getLineStartOffset(line_num); - final PsiElement here_elt = getNode().getPsi(); - line_num = doc.getLineNumber(here_elt.getTextOffset()); - final int node_col = here_elt.getTextOffset() - doc.getLineStartOffset(line_num); - final int padding = item_col - node_col; + int lineNum = doc.getLineNumber(exprItem.getTextOffset()); + final int itemCol = exprItem.getTextOffset() - doc.getLineStartOffset(lineNum); + final PsiElement hereElt = getNode().getPsi(); + lineNum = doc.getLineNumber(hereElt.getTextOffset()); + final int nodeCol = hereElt.getTextOffset() - doc.getLineStartOffset(lineNum); + final int padding = itemCol - nodeCol; if (padding > 0) { // negative is a syntax error, but possible return Indent.getSpaceIndent(padding); } @@ -984,7 +963,7 @@ public class PyBlock implements ASTBlock { return getSubBlockByIndex(prevIndex).getNode(); } - private static ASTNode getLastNonSpaceChild(ASTNode node, boolean acceptError) { + private static ASTNode getLastNonSpaceChild(@NotNull ASTNode node, boolean acceptError) { ASTNode lastChild = node.getLastChildNode(); while (lastChild != null && (lastChild.getElementType() == TokenType.WHITE_SPACE || (!acceptError && lastChild.getPsi() instanceof PsiErrorElement))) { @@ -993,6 +972,7 @@ public class PyBlock implements ASTBlock { return lastChild; } + @Override public boolean isIncomplete() { // if there's something following us, we're not incomplete if (!PsiTreeUtil.hasErrorElements(myNode.getPsi())) { @@ -1034,7 +1014,7 @@ public class PyBlock implements ASTBlock { return false; } - private static boolean isIncompleteCall(ASTNode node) { + private static boolean isIncompleteCall(@NotNull ASTNode node) { if (node.getElementType() == PyElementTypes.CALL_EXPRESSION) { final PyCallExpression callExpression = (PyCallExpression)node.getPsi(); final PyArgumentList argumentList = callExpression.getArgumentList(); @@ -1045,6 +1025,7 @@ public class PyBlock implements ASTBlock { return false; } + @Override public boolean isLeaf() { return myNode.getFirstChildNode() == null; } diff --git a/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java b/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java index 481db69e0594..8873fe5228c0 100644 --- a/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyAbstractClassInspection.java @@ -91,7 +91,7 @@ public class PyAbstractClassInspection extends PyInspection { return true; } } - for (PyFunction method : pyClass.getMethods(false)) { + for (PyFunction method : pyClass.getMethods()) { if (PyUtil.isDecoratedAsAbstract(method)) { return true; } diff --git a/python/src/com/jetbrains/python/inspections/PyOldStyleClassesInspection.java b/python/src/com/jetbrains/python/inspections/PyOldStyleClassesInspection.java index 532c5a5b4112..a866b36281e2 100644 --- a/python/src/com/jetbrains/python/inspections/PyOldStyleClassesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyOldStyleClassesInspection.java @@ -74,7 +74,7 @@ public class PyOldStyleClassesInspection extends PyInspection { registerProblem(attr, "Old-style class contains __slots__ definition", ProblemHighlightType.GENERIC_ERROR_OR_WARNING, null, quickFixes.toArray(new LocalQuickFix[quickFixes.size()])); } } - for (PyFunction attr : node.getMethods(false)) { + for (PyFunction attr : node.getMethods()) { if ("__getattribute__".equals(attr.getName())) { final ASTNode nameNode = attr.getNameNode(); assert nameNode != null; diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddFieldQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddFieldQuickFix.java index 8029597a5405..5156205aa82f 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/AddFieldQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/AddFieldQuickFix.java @@ -163,7 +163,7 @@ public class AddFieldQuickFix implements LocalQuickFix { appendToMethod(newInit, callback); PsiElement addAnchor = null; - PyFunction[] meths = cls.getMethods(false); + PyFunction[] meths = cls.getMethods(); if (meths.length > 0) addAnchor = meths[0].getPrevSibling(); PyStatementList clsContent = cls.getStatementList(); newInit = (PyFunction) clsContent.addAfter(newInit, addAnchor); diff --git a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java index d0b59e3f7fac..1bfe00a95fa7 100644 --- a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java @@ -888,7 +888,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } } } - for (PyFunction method : containedClass.getMethods(false)) { + for (PyFunction method : containedClass.getMethods()) { if (expr.getText().equals(method.getName())) { actions.add(new UnresolvedReferenceAddSelfQuickFix(expr, qualifier)); } diff --git a/python/src/com/jetbrains/python/packaging/PyCondaPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyCondaPackageManagerImpl.java index d46dce3f0b5a..95f6ef828fee 100644 --- a/python/src/com/jetbrains/python/packaging/PyCondaPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyCondaPackageManagerImpl.java @@ -130,9 +130,9 @@ public class PyCondaPackageManagerImpl extends PyPackageManagerImpl { getCondaOutput("remove", arguments); } - @Nullable + @NotNull @Override - public List getPackages(boolean cachedOnly) throws ExecutionException { + protected List getPackages() throws ExecutionException { final ProcessOutput output = getCondaOutput("list", Lists.newArrayList("-e")); return parseCondaToolOutput(output.getStdout()); } diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java index d7ef61698cf2..dc4506aa15fb 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java @@ -276,8 +276,7 @@ public class PyPackageManagerImpl extends PyPackageManager { } } try { - final String output = getHelperResult(PACKAGING_TOOL, Arrays.asList("list"), false, false, null); - final List packages = parsePackagingToolOutput(output); + final List packages = getPackages(); synchronized (myCacheLock) { myPackagesCache = packages; return new ArrayList(myPackagesCache); @@ -291,6 +290,12 @@ public class PyPackageManagerImpl extends PyPackageManager { } } + @NotNull + protected List getPackages() throws ExecutionException { + final String output = getHelperResult(PACKAGING_TOOL, Arrays.asList("list"), false, false, null); + return parsePackagingToolOutput(output); + } + @Nullable public Set getDependents(@NotNull PyPackage pkg) throws ExecutionException { final List packages = getPackages(false); diff --git a/python/src/com/jetbrains/python/projectView/PyElementNode.java b/python/src/com/jetbrains/python/projectView/PyElementNode.java index dcf0088275dc..17e28cf102a1 100644 --- a/python/src/com/jetbrains/python/projectView/PyElementNode.java +++ b/python/src/com/jetbrains/python/projectView/PyElementNode.java @@ -50,7 +50,7 @@ public class PyElementNode extends BasePsiNode { for (PyClass aClass : pyClass.getNestedClasses()) { result.add(new PyElementNode(myProject, aClass, getSettings())); } - for (PyFunction function : pyClass.getMethods(false)) { + for (PyFunction function : pyClass.getMethods()) { result.add(new PyElementNode(myProject, function, getSettings())); } return result; diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index fc3b8ff5e686..bf32c66b7b60 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -1475,7 +1475,7 @@ public class PyUtil { final PsiDocumentManager manager = PsiDocumentManager.getInstance(statementList.getProject()); final Document document = manager.getDocument(statementList.getContainingFile()); if (document != null) { - final PsiElement container = statementList.getParent(); + final PyStatementListContainer container = (PyStatementListContainer)statementList.getParent(); manager.doPostponedOperationsAndUnblockDocument(document); final String indentation = "\n" + PyIndentUtil.getElementIndent(statementList); // If statement list was empty initially, we need to add some anchor statement ("pass"), so that preceding new line was not @@ -1483,7 +1483,7 @@ public class PyUtil { final String text = statementList.getStatements().length == 0 ? indentation + PyNames.PASS : indentation; document.insertString(statementList.getTextRange().getStartOffset(), text); manager.commitDocument(document); - statementList = ((PyStatementListContainer)container).getStatementList(); + statementList = container.getStatementList(); } } final PsiElement firstChild = statementList.getFirstChild(); diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 056d9dfa8b5c..3fd8de69e7b5 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -463,32 +463,8 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla @Override @NotNull - public PyFunction[] getMethods(final boolean inherited) { - final PyFunction[] thisClassFunctions = - getClassChildren(PythonDialectsTokenSetProvider.INSTANCE.getFunctionDeclarationTokens(), PyFunction.ARRAY_FACTORY); - if (!inherited) { - return thisClassFunctions; - } - // Map to get rid of duplicated (overwritten methods) - final Map result = new HashMap(); - // We get classes in MRO order (hopefully), so last methods are last - for (final PyClass superClass : getAncestorClasses(null)) { - for (final PyFunction function : superClass.getMethods(false)) { - final String functionName = function.getName(); - if (functionName != null) { - result.put(functionName, function); - } - } - } - // We now need to add our own methods - for (final PyFunction function : thisClassFunctions) { - final String functionName = function.getName(); - if (functionName != null) { - result.put(functionName, function); - } - } - final Collection functionsToReturn = result.values(); - return functionsToReturn.toArray(new PyFunction[functionsToReturn.size()]); + public PyFunction[] getMethods() { + return getClassChildren(PythonDialectsTokenSetProvider.INSTANCE.getFunctionDeclarationTokens(), PyFunction.ARRAY_FACTORY); } @Override @@ -611,7 +587,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla // look at @property decorators Map> grouped = new HashMap>(); // group suitable same-named methods, each group defines a property - for (PyFunction method : getMethods(false)) { + for (PyFunction method : getMethods()) { final String methodName = method.getName(); if (name == null || name.equals(methodName)) { List bucket = grouped.get(methodName); @@ -923,7 +899,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla private boolean visitMethods(Processor processor, boolean inherited, boolean skipClassObj, TypeEvalContext context) { - PyFunction[] methods = getMethods(false); + PyFunction[] methods = getMethods(); if (!ContainerUtil.process(methods, processor)) return false; if (inherited) { for (PyClass ancestor : getAncestorClasses(context)) { @@ -1037,7 +1013,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla collectInstanceAttributes(initMethod, result); } Set namesInInit = new HashSet(result.keySet()); - final PyFunction[] methods = getMethods(false); + final PyFunction[] methods = getMethods(); for (PyFunction method : methods) { if (!PyNames.INIT.equals(method.getName())) { collectInstanceAttributes(method, result, namesInInit); diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index a88555bff68e..781391c9a2bf 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -18,6 +18,7 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; @@ -29,10 +30,7 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.stubs.StubElement; -import com.intellij.psi.util.CachedValueProvider; -import com.intellij.psi.util.CachedValuesManager; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.QualifiedName; +import com.intellij.psi.util.*; import com.intellij.util.IncorrectOperationException; import com.intellij.util.PlatformIcons; import com.jetbrains.python.PyElementTypes; @@ -67,6 +65,9 @@ import static com.jetbrains.python.psi.impl.PyCallExpressionHelper.interpretAsMo */ public class PyFunctionImpl extends PyBaseElementImpl implements PyFunction { + private static final Key>> + ATTRIBUTES_KEY = Key.create("attributes"); + public PyFunctionImpl(ASTNode astNode) { super(astNode); } @@ -732,8 +733,28 @@ public class PyFunctionImpl extends PyBaseElementImpl implements @NotNull @Override public List findAttributes() { + /** + * TODO: This method if insanely heavy since it unstubs foreign files. + * Need to save stubs and use them somehow. + * + */ + return CachedValuesManager.getManager(getProject()).getCachedValue(this, ATTRIBUTES_KEY, new CachedValueProvider>() { + @Nullable + @Override + public Result> compute() { + final List result = findAttributesStatic(PyFunctionImpl.this); + return Result.create(result, PsiModificationTracker.MODIFICATION_COUNT); + } + }, false); + } + + /** + * @param self should be this + */ + @NotNull + private static List findAttributesStatic(@NotNull final PsiElement self) { final List result = new ArrayList(); - for (final PyAssignmentStatement statement : new PsiQuery(this).siblings(PyAssignmentStatement.class).getElements()) { + for (final PyAssignmentStatement statement : new PsiQuery(self).siblings(PyAssignmentStatement.class).getElements()) { for (final PyQualifiedExpression targetExpression : new PsiQuery(statement.getTargets()).filter(PyQualifiedExpression.class) .getElements()) { final PyExpression qualifier = targetExpression.getQualifier(); @@ -744,7 +765,7 @@ public class PyFunctionImpl extends PyBaseElementImpl implements if (qualifierReference == null) { continue; } - if (qualifierReference.isReferenceTo(this)) { + if (qualifierReference.isReferenceTo(self)) { result.add(statement); } } diff --git a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java index 3b92da74485e..50c2abb10c93 100644 --- a/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java +++ b/python/src/com/jetbrains/python/psi/search/PySuperMethodsSearchExecutor.java @@ -68,7 +68,7 @@ public class PySuperMethodsSearchExecutor implements QueryExecutor { public static List getAllDeclaredAttributeNames(@NotNull PyClass pyClass) { final List members = ContainerUtil.concat(pyClass.getInstanceAttributes(), pyClass.getClassAttributes(), - Arrays.asList(pyClass.getMethods(false))); + Arrays.asList(pyClass.getMethods())); return ContainerUtil.mapNotNull(members, new Function() { @Override diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 09aab39c0759..ae0450ecee0a 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -230,7 +230,7 @@ public class PyTypeChecker { boolean isDefinition, @NotNull TypeEvalContext context) { final Set attributes = new HashSet(); - for (PyFunction function : cls.getMethods(false)) { + for (PyFunction function : cls.getMethods()) { attributes.add(function.getName()); } for (PyTargetExpression instanceAttribute : cls.getInstanceAttributes()) { diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeUtil.java b/python/src/com/jetbrains/python/psi/types/PyTypeUtil.java index a083a6e39bce..429a76aaca00 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeUtil.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeUtil.java @@ -23,7 +23,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Collection; import java.util.List; /** @@ -36,18 +35,13 @@ public final class PyTypeUtil { } /** - * Returns members of certain type from {@link PyClassLikeType} - * - * @param type type itself - * @param expectedMemberType expected member type - * @param context context to use - * @param expected member type - * @return collection of members + * Returns members of certain type from {@link PyClassLikeType}. */ @NotNull - public static Collection getMembersOfType(@NotNull final PyClassLikeType type, - @NotNull final Class expectedMemberType, - @NotNull final TypeEvalContext context) { + public static List getMembersOfType(@NotNull final PyClassLikeType type, + @NotNull final Class expectedMemberType, + boolean inherited, + @NotNull final TypeEvalContext context) { final List result = new ArrayList(); type.visitMembers(new Processor() { @@ -60,7 +54,7 @@ public final class PyTypeUtil { } return true; } - }, true, context); + }, inherited, context); return result; } diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java index 1ad4f03c53cf..4c5996cc6ddd 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java @@ -59,7 +59,7 @@ class MethodsManager extends MembersManager { @Override public boolean hasConflict(@NotNull final PyFunction member, @NotNull final PyClass aClass) { - return NamePredicate.hasElementWithSameName(member, Arrays.asList(aClass.getMethods(false))); + return NamePredicate.hasElementWithSameName(member, Arrays.asList(aClass.getMethods())); } @NotNull @@ -79,7 +79,7 @@ class MethodsManager extends MembersManager { @NotNull @Override protected List getMembersCouldBeMoved(@NotNull final PyClass pyClass) { - return FluentIterable.from(Arrays.asList(pyClass.getMethods(false))).filter(new NamelessFilter()).filter(NO_PROPERTIES).toList(); + return FluentIterable.from(Arrays.asList(pyClass.getMethods())).filter(new NamelessFilter()).filter(NO_PROPERTIES).toList(); } @Override diff --git a/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java b/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java index 9a7161c8d057..21c800a08ee4 100644 --- a/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java +++ b/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java @@ -201,7 +201,7 @@ public class PyExtractMethodUtil { scope.add(owner); final PyClass containingClass = ((PyFunction)owner).getContainingClass(); if (containingClass != null) { - for (PyFunction function : containingClass.getMethods(false)) { + for (PyFunction function : containingClass.getMethods()) { if (!function.equals(owner) && !function.equals(generatedMethod)) { scope.add(function); } diff --git a/python/src/com/jetbrains/python/run/PythonCommandLineState.java b/python/src/com/jetbrains/python/run/PythonCommandLineState.java index 67b17b143a56..419bd0c65acd 100644 --- a/python/src/com/jetbrains/python/run/PythonCommandLineState.java +++ b/python/src/com/jetbrains/python/run/PythonCommandLineState.java @@ -16,6 +16,7 @@ package com.jetbrains.python.run; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.intellij.execution.DefaultExecutionResult; import com.intellij.execution.ExecutionException; @@ -51,7 +52,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingProjectManager; import com.intellij.remote.RemoteProcessControl; import com.intellij.util.PlatformUtils; -import com.intellij.util.containers.HashMap; import com.jetbrains.python.console.PyDebugConsoleBuilder; import com.jetbrains.python.debugger.PyDebugRunner; import com.jetbrains.python.debugger.PyDebuggerOptionsProvider; @@ -278,16 +278,14 @@ public abstract class PythonCommandLineState extends CommandLineState { } protected static void initEnvironment(Project project, GeneralCommandLine commandLine, PythonRunParams myConfig) { - Map env = myConfig.getEnvs(); - if (env == null) { - env = new HashMap(); - } - else { - env = new HashMap(env); - } + Map env = Maps.newHashMap(); setupEncodingEnvs(env, commandLine.getCharset()); + if (myConfig.getEnvs() != null) { + env.putAll(myConfig.getEnvs()); + } + addCommonEnvironmentVariables(env); commandLine.getEnvironment().clear(); diff --git a/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java b/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java index 40115fcdb343..ecf72053f29f 100644 --- a/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java +++ b/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java @@ -60,7 +60,7 @@ public class PythonAtTestConfigurationProducer extends } private static boolean hasTestFunction(@NotNull final PyClass pyClass) { - PyFunction[] methods = pyClass.getMethods(false); + PyFunction[] methods = pyClass.getMethods(); for (PyFunction function : methods) { PyDecoratorList decorators = function.getDecoratorList(); if (decorators == null) continue; diff --git a/python/src/com/jetbrains/python/testing/doctest/PythonDocTestUtil.java b/python/src/com/jetbrains/python/testing/doctest/PythonDocTestUtil.java index 351bbc01fd34..e0360ae5a6f5 100644 --- a/python/src/com/jetbrains/python/testing/doctest/PythonDocTestUtil.java +++ b/python/src/com/jetbrains/python/testing/doctest/PythonDocTestUtil.java @@ -58,7 +58,7 @@ public class PythonDocTestUtil { } public static boolean isDocTestClass(PyClass pyClass) { - for (PyFunction cls : pyClass.getMethods(false)) { + for (PyFunction cls : pyClass.getMethods()) { if (isDocTestFunction(cls)) { return true; } diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java b/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java index 4bc36647257c..a888e1292da9 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java @@ -83,7 +83,7 @@ public class PyTestUtil { if (className == null) return false; final String name = className.toLowerCase(); if (name.startsWith("test")) { - for (PyFunction cls : pyClass.getMethods(false)) { + for (PyFunction cls : pyClass.getMethods()) { if (isPyTestFunction(cls)) { return true; } diff --git a/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java b/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java index 646b7b8fab3e..3e7cc9f2bc63 100644 --- a/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java +++ b/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java @@ -171,7 +171,7 @@ public class Pep8ExternalAnnotator extends ExternalAnnotator allSdks = PythonSdkType.getAllSdks(); Collections.sort(allSdks, PreferredSdkComparator.INSTANCE); for (Sdk sdk : allSdks) { diff --git a/python/testData/formatter/continuationIndentIsNotUsedForNestedFunctionCallsInWithStatement_after.py b/python/testData/formatter/continuationIndentIsNotUsedForNestedFunctionCallsInWithStatement_after.py index c867a3f0451a..9a4e5063b2ab 100644 --- a/python/testData/formatter/continuationIndentIsNotUsedForNestedFunctionCallsInWithStatement_after.py +++ b/python/testData/formatter/continuationIndentIsNotUsedForNestedFunctionCallsInWithStatement_after.py @@ -1,4 +1,4 @@ with raises_assertion( has_string('Missing download_urls: {}, {}'.format( - self.other_download_url, self.another_download_url))): + self.other_download_url, self.another_download_url))): fixture.assert_detail_page_yields_expected() diff --git a/python/testData/formatter/hangingIndentInNamedArgumentValue_after.py b/python/testData/formatter/hangingIndentInNamedArgumentValue_after.py index 4585528e01cd..1102984b4b98 100644 --- a/python/testData/formatter/hangingIndentInNamedArgumentValue_after.py +++ b/python/testData/formatter/hangingIndentInNamedArgumentValue_after.py @@ -1,3 +1,3 @@ funcWithLongName(x=[ ], - y=42) + y=42) diff --git a/python/testData/formatter/noAlignForMethodArguments_after.py b/python/testData/formatter/noAlignForMethodArguments_after.py index 5682f4ca4f45..740f638adf4c 100644 --- a/python/testData/formatter/noAlignForMethodArguments_after.py +++ b/python/testData/formatter/noAlignForMethodArguments_after.py @@ -2,4 +2,4 @@ def long_method_name(bar, baz): pass long_method_name("long string one", - "long string two") + "long string two") diff --git a/python/testData/formatter/noWrapBeforeParen_after.py b/python/testData/formatter/noWrapBeforeParen_after.py index 5ab3054984db..003f387c408c 100644 --- a/python/testData/formatter/noWrapBeforeParen_after.py +++ b/python/testData/formatter/noWrapBeforeParen_after.py @@ -4,4 +4,4 @@ def foo(): if comments: for comment in comments: record += ' \n' + ca + '=' + quoteattr(comment[ca]) + ' ' for ca in comment) + '/>\n' diff --git a/python/testData/formatter/setLiteralInArgList_after.py b/python/testData/formatter/setLiteralInArgList_after.py index 9c2f75d6dca6..48bec3381227 100644 --- a/python/testData/formatter/setLiteralInArgList_after.py +++ b/python/testData/formatter/setLiteralInArgList_after.py @@ -1,3 +1,3 @@ self.assertEqual( - {"000000000000", "111111111111"}, - foo['bar']['baz']) + {"000000000000", "111111111111"}, + foo['bar']['baz']) diff --git a/python/testData/inspections/PyAbstractClassInspection/notImplementedOverriddenInParent.py b/python/testData/inspections/PyAbstractClassInspection/notImplementedOverriddenInParent.py new file mode 100644 index 000000000000..b81c3b6ab7f4 --- /dev/null +++ b/python/testData/inspections/PyAbstractClassInspection/notImplementedOverriddenInParent.py @@ -0,0 +1,12 @@ +class A: + def foo(self): + raise NotImplementedError + + +class B(A): + def foo(self): + print('foo') + + +class C(B): + pass diff --git a/python/testData/intentions/afterReturnTypeInPy3AnnotationLocalFunction.py b/python/testData/intentions/afterReturnTypeInPy3AnnotationLocalFunction.py new file mode 100644 index 000000000000..9d433078a827 --- /dev/null +++ b/python/testData/intentions/afterReturnTypeInPy3AnnotationLocalFunction.py @@ -0,0 +1,4 @@ +def foo() -> object: + @decorator + def bar(): + pass \ No newline at end of file diff --git a/python/testData/intentions/afterReturnTypeInPy3AnnotationNoColon.py b/python/testData/intentions/afterReturnTypeInPy3AnnotationNoColon.py new file mode 100644 index 000000000000..9d433078a827 --- /dev/null +++ b/python/testData/intentions/afterReturnTypeInPy3AnnotationNoColon.py @@ -0,0 +1,4 @@ +def foo() -> object: + @decorator + def bar(): + pass \ No newline at end of file diff --git a/python/testData/intentions/beforeReturnTypeInPy3AnnotationLocalFunction.py b/python/testData/intentions/beforeReturnTypeInPy3AnnotationLocalFunction.py new file mode 100644 index 000000000000..e3c6d23b4d68 --- /dev/null +++ b/python/testData/intentions/beforeReturnTypeInPy3AnnotationLocalFunction.py @@ -0,0 +1,4 @@ +def foo(): + @decorator + def bar(): + pass \ No newline at end of file diff --git a/python/testData/intentions/beforeReturnTypeInPy3AnnotationNoColon.py b/python/testData/intentions/beforeReturnTypeInPy3AnnotationNoColon.py new file mode 100644 index 000000000000..2ea3c54799c1 --- /dev/null +++ b/python/testData/intentions/beforeReturnTypeInPy3AnnotationNoColon.py @@ -0,0 +1,4 @@ +def foo() + @decorator + def bar(): + pass \ No newline at end of file diff --git a/python/testData/refactoring/introduceVariable/functionCallWithCommentNotInlined.after.py b/python/testData/refactoring/introduceVariable/functionCallWithCommentNotInlined.after.py index 3140c9b2ab96..f73d8462c0c9 100644 --- a/python/testData/refactoring/introduceVariable/functionCallWithCommentNotInlined.after.py +++ b/python/testData/refactoring/introduceVariable/functionCallWithCommentNotInlined.after.py @@ -1,8 +1,8 @@ import subprocess as sp a = sp.check_output( - args=['python', '-c', 'print("Spam")'], - # read errors too - stderr=sp.STDOUT + args=['python', '-c', 'print("Spam")'], + # read errors too + stderr=sp.STDOUT ) print(a) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java b/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java index c5e489c06485..203b462c5a44 100644 --- a/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java +++ b/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java @@ -205,7 +205,7 @@ public class PyControlFlowBuilderTest extends LightMarkedTestCase { configureByFile(testName + ".py"); final String fullPath = getTestDataPath() + testName + ".txt"; final PyClass pyClass = ((PyFile) myFile).getTopLevelClasses().get(0); - final ControlFlow flow = ControlFlowCache.getControlFlow(pyClass.getMethods(false)[0]); + final ControlFlow flow = ControlFlowCache.getControlFlow(pyClass.getMethods()[0]); check(fullPath, flow); } @@ -214,7 +214,7 @@ public class PyControlFlowBuilderTest extends LightMarkedTestCase { configureByFile(testName + ".py"); final String fullPath = getTestDataPath() + testName + ".txt"; final PyClass pyClass = ((PyFile) myFile).getTopLevelClasses().get(0); - final ControlFlow flow = ControlFlowCache.getControlFlow(pyClass.getMethods(false)[0]); + final ControlFlow flow = ControlFlowCache.getControlFlow(pyClass.getMethods()[0]); check(fullPath, flow); } diff --git a/python/testSrc/com/jetbrains/python/PyIndentTest.java b/python/testSrc/com/jetbrains/python/PyIndentTest.java index 0164e14fc5ce..d6c09b817227 100644 --- a/python/testSrc/com/jetbrains/python/PyIndentTest.java +++ b/python/testSrc/com/jetbrains/python/PyIndentTest.java @@ -16,7 +16,6 @@ package com.jetbrains.python; import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.command.CommandProcessor; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.jetbrains.python.fixtures.PyTestCase; @@ -200,7 +199,7 @@ public class PyIndentTest extends PyTestCase { public void testEnterInNonEmptyArgList() { // PY-1947 doTest("Task(params=1)", "Task(\n" + - " params=1)"); + " params=1)"); } public void testEnterInNonClosedArgList() { // PY-4863 diff --git a/python/testSrc/com/jetbrains/python/PyOverrideTest.java b/python/testSrc/com/jetbrains/python/PyOverrideTest.java index e89eb6c6bb7c..53a5d7f55d12 100644 --- a/python/testSrc/com/jetbrains/python/PyOverrideTest.java +++ b/python/testSrc/com/jetbrains/python/PyOverrideTest.java @@ -34,7 +34,7 @@ import java.util.Collections; public class PyOverrideTest extends PyTestCase { private void doTest() { myFixture.configureByFile("override/" + getTestName(true) + ".py"); - PyFunction toOverride = getTopLevelClass(0).getMethods(false) [0]; + PyFunction toOverride = getTopLevelClass(0).getMethods() [0]; PyOverrideImplementUtil.overrideMethods(myFixture.getEditor(), getTopLevelClass(1), Collections.singletonList(new PyMethodMember(toOverride)), false); myFixture.checkResultByFile("override/" + getTestName(true) + "_after.py", true); @@ -91,7 +91,7 @@ public class PyOverrideTest extends PyTestCase { public void testInnerClass() { // PY-10976 myFixture.configureByFile("override/" + getTestName(true) + ".py"); - PyFunction toOverride = getTopLevelClass(0).getMethods(false)[0]; + PyFunction toOverride = getTopLevelClass(0).getMethods()[0]; PyClass pyClass = getTopLevelClass(1).getNestedClasses()[0]; PyOverrideImplementUtil.overrideMethods(myFixture.getEditor(), pyClass, Collections.singletonList(new PyMethodMember(toOverride)), false); @@ -100,7 +100,7 @@ public class PyOverrideTest extends PyTestCase { public void testInnerFunctionClass() { myFixture.configureByFile("override/" + getTestName(true) + ".py"); - PyFunction toOverride = getTopLevelClass(0).getMethods(false)[0]; + PyFunction toOverride = getTopLevelClass(0).getMethods()[0]; final PsiElement element = myFixture.getElementAtCaret(); PyOverrideImplementUtil.overrideMethods(myFixture.getEditor(), PsiTreeUtil.getParentOfType(element, PyClass.class, false), Collections.singletonList(new PyMethodMember(toOverride)), false); @@ -120,7 +120,7 @@ public class PyOverrideTest extends PyTestCase { public void testImplement() { myFixture.configureByFile("override/" + getTestName(true) + ".py"); - PyFunction toImplement = getTopLevelClass(0).getMethods(false)[1]; + PyFunction toImplement = getTopLevelClass(0).getMethods()[1]; PyOverrideImplementUtil.overrideMethods(myFixture.getEditor(), getTopLevelClass(1), Collections.singletonList(new PyMethodMember(toImplement)), true); myFixture.checkResultByFile("override/" + getTestName(true) + "_after.py", true); diff --git a/python/testSrc/com/jetbrains/python/PyStubsTest.java b/python/testSrc/com/jetbrains/python/PyStubsTest.java index f553adf47d15..6b63660f8be5 100644 --- a/python/testSrc/com/jetbrains/python/PyStubsTest.java +++ b/python/testSrc/com/jetbrains/python/PyStubsTest.java @@ -70,7 +70,7 @@ public class PyStubsTest extends PyTestCase { assertEquals("staticField", attrs.get(0).getName()); assertTrue(attrs.get(0).getAssignedQName().matches("deco")); - final PyFunction[] methods = pyClass.getMethods(false); + final PyFunction[] methods = pyClass.getMethods(); assertEquals(2, methods.length); assertEquals("__init__", methods [0].getName()); assertEquals("fooFunction", methods [1].getName()); @@ -117,7 +117,7 @@ public class PyStubsTest extends PyTestCase { Property prop = pyClass.findProperty("value", true, null); Maybe maybe_function = prop.getGetter(); assertTrue(maybe_function.isDefined()); - assertEquals(pyClass.getMethods(false)[0], maybe_function.value()); + assertEquals(pyClass.getMethods()[0], maybe_function.value()); Property setvalueProp = pyClass.findProperty("setvalue", true, null); Maybe setter = setvalueProp.getSetter(); @@ -130,10 +130,10 @@ public class PyStubsTest extends PyTestCase { prop = pyClass.findProperty("x", true, null); maybe_function = prop.getGetter(); assertTrue(maybe_function.isDefined()); - assertEquals(pyClass.getMethods(false)[0], maybe_function.value()); + assertEquals(pyClass.getMethods()[0], maybe_function.value()); maybe_function = prop.getSetter(); assertTrue(maybe_function.isDefined()); - assertEquals(pyClass.getMethods(false)[1], maybe_function.value()); + assertEquals(pyClass.getMethods()[1], maybe_function.value()); // ...and the juice: assertNotParsed(file); @@ -332,7 +332,7 @@ public class PyStubsTest extends PyTestCase { public void testWrappedStaticMethod() { final PyFileImpl file = (PyFileImpl) getTestFile(); final PyClass pyClass = file.getTopLevelClasses().get(0); - final PyFunction[] methods = pyClass.getMethods(false); + final PyFunction[] methods = pyClass.getMethods(); assertEquals(1, methods.length); final PyFunction.Modifier modifier = methods[0].getModifier(); assertEquals(PyFunction.Modifier.STATICMETHOD, modifier); diff --git a/python/testSrc/com/jetbrains/python/inspections/PyAbstractClassInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyAbstractClassInspectionTest.java index 78c2b5f8e4bd..d5e5ad3127e8 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyAbstractClassInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyAbstractClassInspectionTest.java @@ -52,6 +52,11 @@ public class PyAbstractClassInspectionTest extends PyInspectionTestCase { doTest(); } + // PY-16776 + public void testNotImplementedOverriddenInParent() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() { diff --git a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java index 7d23e79313ff..3d218448a462 100644 --- a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java @@ -359,6 +359,15 @@ public class PyIntentionTest extends PyTestCase { public void testReturnTypeInPy3Annotation2() { //PY-8783 doTest(PyBundle.message("INTN.specify.return.type.in.annotation"), LanguageLevel.PYTHON32); } + + // PY-17094 + public void testReturnTypeInPy3AnnotationLocalFunction() { + doTest(PyBundle.message("INTN.specify.return.type.in.annotation"), LanguageLevel.PYTHON32); + } + + public void testReturnTypeInPy3AnnotationNoColon() { + doTest(PyBundle.message("INTN.specify.return.type.in.annotation"), LanguageLevel.PYTHON32); + } public void testTypeAnnotation3() { //PY-7087 doTypeAnnotationTest(); diff --git a/python/testSrc/com/jetbrains/python/refactoring/classes/PyDependenciesComparatorTest.java b/python/testSrc/com/jetbrains/python/refactoring/classes/PyDependenciesComparatorTest.java index b3be3825f970..ba952c3f2456 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/classes/PyDependenciesComparatorTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/classes/PyDependenciesComparatorTest.java @@ -22,7 +22,7 @@ public class PyDependenciesComparatorTest extends PyTestCase { @SuppressWarnings("ConstantConditions") // Can't be null (class has docstring) PsiElement docStringExpression = clazz.getDocStringExpression().getParent(); - PyFunction method = clazz.getMethods(false)[0]; + PyFunction method = clazz.getMethods()[0]; PsiElement classField = clazz.getClassAttributes().get(0).getParent(); final List elementList = new ArrayList(); diff --git a/resources-en/src/inspectionDescriptions/Guava.html b/resources-en/src/inspectionDescriptions/Guava.html index 2e21dbe99177..8f3a5e3fe614 100644 --- a/resources-en/src/inspectionDescriptions/Guava.html +++ b/resources-en/src/inspectionDescriptions/Guava.html @@ -1,6 +1,11 @@ Inspection detects usages of Guava's functional primitives like -c.g.c.c.FluentIterable, c.g.c.b.Optional, c.g.c.b.Function and c.g.c.b.Supplier. +FluentIterable, Optional, Function, Predicate and Supplier. +
+
+This inspection only reports if the project +or module is configured to use a language level +of 8 or higher. \ No newline at end of file diff --git a/spellchecker/src/com/intellij/spellchecker/english.dic b/spellchecker/src/com/intellij/spellchecker/english.dic index 914f996cb13b..424511cd9f28 100644 --- a/spellchecker/src/com/intellij/spellchecker/english.dic +++ b/spellchecker/src/com/intellij/spellchecker/english.dic @@ -35234,6 +35234,7 @@ appellation's appellations append appendage +appendable appendage's appendages appendectomies diff --git a/xml/dom-tests/tests/com/intellij/util/xml/DomConcurrencyStressTest.java b/xml/dom-tests/tests/com/intellij/util/xml/DomConcurrencyStressTest.java index c625a6a2070a..82f2f804c5c8 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/DomConcurrencyStressTest.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/DomConcurrencyStressTest.java @@ -27,7 +27,10 @@ import com.intellij.psi.xml.XmlTag; import com.intellij.semantic.SemService; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.Timings; +import com.intellij.util.Function; +import com.intellij.util.Processor; import com.intellij.util.TimeoutUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xml.impl.DomFileElementImpl; import com.intellij.util.xml.impl.DomTestCase; import com.intellij.util.xml.reflect.DomExtender; @@ -35,6 +38,7 @@ import com.intellij.util.xml.reflect.DomExtenderEP; import com.intellij.util.xml.reflect.DomExtensionsRegistrar; import org.jetbrains.annotations.NotNull; +import java.util.Collections; import java.util.List; import java.util.Random; import java.util.concurrent.CountDownLatch; @@ -115,27 +119,42 @@ public class DomConcurrencyStressTest extends DomTestCase { for (int i=0; i exc = Ref.create(null); - final CountDownLatch reads = new CountDownLatch(8); - for (int j = 0; j < 8; j++) { - new Thread("dom concurrency"){ - @Override - public void run() { - try { - runnable.run(); + int N = 8; + final CountDownLatch reads = new CountDownLatch(N); + List threads = ContainerUtil.map(Collections.nCopies(N, ""), new Function() { + @Override + public Thread fun(String s) { + return new Thread("dom concurrency") { + @Override + public void run() { + try { + runnable.run(); + } + catch (Throwable e) { + exc.set(e); + } + finally { + reads.countDown(); + } } - catch (Throwable e) { - exc.set(e); - } - finally { - reads.countDown(); - } - } - }.start(); - } + }; + } + }); + ContainerUtil.process(threads, new Processor() { + @Override + public boolean process(Thread thread) { + thread.start(); + return true; + } + }); + reads.await(); if (!exc.isNull()) { throw exc.get(); } + for (Thread thread : threads) { + thread.join(); + } } } diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/validation/RngParser.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/validation/RngParser.java index b7a8492df582..38fd5ee0ecc1 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/validation/RngParser.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/validation/RngParser.java @@ -16,14 +16,13 @@ package org.intellij.plugins.relaxNG.validation; +import com.intellij.javaee.UriUtil; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.AtomicNotNullLazyValue; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.util.CachedValue; @@ -31,7 +30,6 @@ import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.xml.XmlFile; import com.intellij.util.containers.ContainerUtil; -import com.intellij.xml.util.XmlUtil; import com.thaiopensource.datatype.xsd.DatatypeLibraryFactoryImpl; import com.thaiopensource.relaxng.impl.SchemaReaderImpl; import com.thaiopensource.util.PropertyMap; @@ -160,6 +158,7 @@ public class RngParser { private static Parseable createParsable(final PsiFile file, final ErrorHandler eh) { final InputSource source = makeInputSource(file); + final VirtualFile virtualFile = file.getVirtualFile(); if (file.getFileType() == RncFileType.getInstance()) { return new CompactParseable(source, eh) { @@ -167,7 +166,7 @@ public class RngParser { public ParsedPattern parseInclude(String uri, SchemaBuilder schemaBuilder, IncludedGrammar g, String inheritedNs) throws BuildException, IllegalSchemaException { - return super.parseInclude(resolveURI(file, uri), schemaBuilder, g, inheritedNs); + return super.parseInclude(resolveURI(virtualFile, uri), schemaBuilder, g, inheritedNs); } }; } else { @@ -176,27 +175,16 @@ public class RngParser { public ParsedPattern parseInclude(String uri, SchemaBuilder schemaBuilder, IncludedGrammar g, String inheritedNs) throws BuildException, IllegalSchemaException { - return super.parseInclude(resolveURI(file, uri), schemaBuilder, g, inheritedNs); + return super.parseInclude(resolveURI(virtualFile, uri), schemaBuilder, g, inheritedNs); } }; } } - public static String resolveURI(PsiFile descriptorFile, String s) { - final PsiFile file = XmlUtil.findXmlFile(descriptorFile, s); - + private static String resolveURI(VirtualFile descriptorFile, String s) { + final VirtualFile file = UriUtil.findRelativeFile(s, descriptorFile); if (file != null) { - final VirtualFile virtualFile = file.getVirtualFile(); - if (virtualFile != null) { - final PsiDocumentManager dm = PsiDocumentManager.getInstance(file.getProject()); - final Document d = dm.getCachedDocument(file); - if (d != null) { - // TODO: fix. write action + saving -> deadlock -// dm.commitDocument(d); -// FileDocumentManager.getInstance().saveDocument(d); - } - s = VfsUtilCore.fixIDEAUrl(virtualFile.getUrl()); - } + s = VfsUtilCore.fixIDEAUrl(file.getUrl()); } return s; } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java index 6a393d7a374f..c479ceba74be 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlUtil.java @@ -318,22 +318,7 @@ public class HtmlUtil { final String tagName = tokenizer.nextToken(); if (tagName.length() == 0) continue; - descriptors[index++] = new XmlElementDescriptorImpl(null) { - @Override - public String getName(PsiElement context) { - return tagName; - } - - @Override - public String getDefaultName() { - return tagName; - } - - @Override - public boolean allowElementsFromNamespace(final String namespace, final XmlTag context) { - return true; - } - }; + descriptors[index++] = new CustomXmlTagDescriptor(tagName); } return descriptors; @@ -684,4 +669,28 @@ public class HtmlUtil { public static boolean isScriptTag(@Nullable XmlTag tag) { return tag != null && tag.getLocalName().equalsIgnoreCase(SCRIPT_TAG_NAME); } + + public static class CustomXmlTagDescriptor extends XmlElementDescriptorImpl { + private final String myTagName; + + public CustomXmlTagDescriptor(String tagName) { + super(null); + myTagName = tagName; + } + + @Override + public String getName(PsiElement context) { + return myTagName; + } + + @Override + public String getDefaultName() { + return myTagName; + } + + @Override + public boolean allowElementsFromNamespace(final String namespace, final XmlTag context) { + return true; + } + } }