diff --git a/build/scripts/utils.gant b/build/scripts/utils.gant index b0ac9466ad33..71ad2a345d8f 100644 --- a/build/scripts/utils.gant +++ b/build/scripts/utils.gant @@ -862,10 +862,11 @@ binding.setVariable("buildCrossPlatformZip", { String zipPath, String sandbox, L } ant.copy(todir: "$zipDir/bin/mac") { fileset(dir: "$distMac/bin") { - include(name: "idea*.vmoptions") + include(name: "idea.vmoptions") include(name: "idea.properties") } } + ant.copy(file: "$distMac/bin/idea.vmoptions", tofile: "$zipDir/bin/mac/idea64.vmoptions") ant.zip(zipfile: zipPath, duplicate: "fail") { commonPaths.each { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index f691f50a9ad3..bf138c8433cd 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -920,9 +920,12 @@ public class GenericsHighlightUtil { } try { MethodSignatureBackedByPsiMethod superMethod = SuperMethodsSearch.search(method, null, true, false).findFirst(); - if (superMethod != null && method.getContainingClass().isInterface() && "clone".equals(superMethod.getName())) { - final PsiClass containingClass = superMethod.getMethod().getContainingClass(); - if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName())) { + if (superMethod != null && method.getContainingClass().isInterface()) { + final PsiMethod psiMethod = superMethod.getMethod(); + final PsiClass containingClass = psiMethod.getContainingClass(); + if (containingClass != null && + CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) && + psiMethod.hasModifierProperty(PsiModifier.PROTECTED)) { superMethod = null; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/LambdaCompletionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/FunctionalExpressionCompletionProvider.java similarity index 50% rename from java/java-impl/src/com/intellij/codeInsight/completion/LambdaCompletionProvider.java rename to java/java-impl/src/com/intellij/codeInsight/completion/FunctionalExpressionCompletionProvider.java index 51990eafa3de..43789e6e4975 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/LambdaCompletionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/FunctionalExpressionCompletionProvider.java @@ -20,6 +20,8 @@ import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.codeInsight.lookup.AutoCompletionPolicy; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorModificationUtil; import com.intellij.openapi.project.Project; @@ -27,28 +29,32 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.impl.source.resolve.JavaResolveUtil; import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.Function; import com.intellij.util.ProcessingContext; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * User: anna */ -public class LambdaCompletionProvider extends CompletionProvider { +public class FunctionalExpressionCompletionProvider extends CompletionProvider { @Override protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) { - result.addAllElements(getLambdaVariants(parameters)); + result.addAllElements(getLambdaVariants(parameters, false)); } - static List getLambdaVariants(@NotNull CompletionParameters parameters) { + static List getLambdaVariants(@NotNull CompletionParameters parameters, boolean prioritize) { if (!PsiUtil.isLanguageLevel8OrHigher(parameters.getOriginalFile())) return Collections.emptyList(); List result = ContainerUtil.newArrayList(); @@ -56,15 +62,15 @@ public class LambdaCompletionProvider extends CompletionProvider {}").withInsertHandler(new InsertHandler() { + LookupElementBuilder.create(functionalInterfaceMethod, paramsString).withPresentableText(paramsString + " -> {}").withInsertHandler(new InsertHandler() { @Override public void handleInsert(InsertionContext context, LookupElement item) { final Editor editor = context.getEditor(); EditorModificationUtil.insertStringAtCaret(editor, " -> "); } - }); - result.add(builder.withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE)); + }).withIcon(AllIcons.Nodes.AnonymousClass); + LookupElement lambdaElement = builder.withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE); + if (prioritize) { + lambdaElement = PrioritizedLookupElement.withPriority(lambdaElement, 1); + } + result.add(lambdaElement); + + if (params.length == 1) { + final PsiType expectedReturnType = substitutor.substitute(functionalInterfaceMethod.getReturnType()); + if (expectedReturnType != null) { + final PsiClass paramClass = PsiUtil.resolveClassInClassTypeOnly(params[0].getType()); + if (paramClass != null && !paramClass.hasTypeParameters()) { + final Set visited = new HashSet(); + for (PsiMethod psiMethod : paramClass.getAllMethods()) { + final PsiType returnType = psiMethod.getReturnType(); + if (returnType != null && + psiMethod.getParameterList().getParametersCount() == 0 && + visited.add(psiMethod.getName()) && + !psiMethod.hasModifierProperty(PsiModifier.STATIC) && + JavaResolveUtil.isAccessible(psiMethod, null, psiMethod.getModifierList(), originalPosition, null, null) && + TypeConversionUtil.isAssignable(expectedReturnType, returnType)) { + LookupElement methodRefLookupElement = LookupElementBuilder + .create(psiMethod) + .withPresentableText(paramClass.getName() + "::" + psiMethod.getName()) + .withInsertHandler(new InsertHandler() { + @Override + public void handleInsert(InsertionContext context, LookupElement item) { + final int startOffset = context.getStartOffset(); + final Document document = context.getDocument(); + final PsiFile file = context.getFile(); + document.insertString(startOffset, "::"); + JavaCompletionUtil.insertClassReference(paramClass, file, startOffset); + } + }) + .withIcon(AllIcons.Nodes.AnonymousClass) + .withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE); + if (prioritize && psiMethod.getContainingClass() == paramClass) { + methodRefLookupElement = PrioritizedLookupElement.withPriority(methodRefLookupElement, 1); + } + result.add(methodRefLookupElement); + } + } + } + } + } } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 9789ec76a99a..5c42a1f0deaa 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -225,9 +225,7 @@ public class JavaCompletionContributor extends CompletionContributor { } if (JavaSmartCompletionContributor.LAMBDA.accepts(parameters.getPosition())) { - for (LookupElement element : LambdaCompletionProvider.getLambdaVariants(parameters)) { - result.addElement(PrioritizedLookupElement.withPriority(element, 1)); - } + result.addAllElements(FunctionalExpressionCompletionProvider.getLambdaVariants(parameters, true)); } PrefixMatcher matcher = result.getPrefixMatcher(); 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 21ffb966c1a4..6e6c2d7611ff 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -359,7 +359,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { } }); - extend(CompletionType.SMART, LAMBDA, new LambdaCompletionProvider()); + extend(CompletionType.SMART, LAMBDA, new FunctionalExpressionCompletionProvider()); extend(CompletionType.SMART, METHOD_REFERENCE, new MethodReferenceCompletionProvider()); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/AddImportAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/AddImportAction.java index 74f96d42f076..3b11cc5c7848 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/AddImportAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/AddImportAction.java @@ -30,6 +30,7 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.PopupStep; @@ -196,7 +197,12 @@ public class AddImportAction implements QuestionAction { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - _addImport(ref, targetClass); + DumbService.getInstance(myProject).withAlternativeResolveEnabled(new Runnable() { + @Override + public void run() { + _addImport(ref, targetClass); + } + }); } }); } diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/util/JavaPostfixTemplatesUtils.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/util/JavaPostfixTemplatesUtils.java index 0a81e59c1ed2..38d30e1a3a23 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/util/JavaPostfixTemplatesUtils.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/util/JavaPostfixTemplatesUtils.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.template.postfix.templates.PostfixTemplateExpres import com.intellij.codeInsight.template.postfix.templates.PostfixTemplateExpressionSelectorBase; import com.intellij.codeInsight.template.postfix.templates.PostfixTemplatePsiInfo; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Conditions; import com.intellij.psi.*; @@ -33,6 +34,7 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.List; import static com.intellij.openapi.util.Conditions.and; @@ -80,6 +82,8 @@ public abstract class JavaPostfixTemplatesUtils { @NotNull @Override public List getExpressions(@NotNull PsiElement context, @NotNull Document document, int offset) { + if (DumbService.getInstance(context.getProject()).isDumb()) return Collections.emptyList(); + List expressions = super.getExpressions(context, document, offset); if (!expressions.isEmpty()) return expressions; diff --git a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java index 3f7575827d00..e2a7f417fb62 100644 --- a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java @@ -509,7 +509,7 @@ public class GenericsUtil { final PsiType bound = ((PsiWildcardType)type).getBound(); return eliminateWildcards(bound != null ? bound : ((PsiWildcardType)type).getExtendsBound(), false);//object } else if (type instanceof PsiCapturedWildcardType && !eliminateInTypeArguments) { - return eliminateWildcards(((PsiCapturedWildcardType)type).getWildcard(), eliminateInTypeArguments); + return ((PsiCapturedWildcardType)type).getUpperBound(); } return type; } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java index b342f601b6fb..4c522a785bb6 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java @@ -16,6 +16,9 @@ package com.intellij.psi; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.RecursionGuard; +import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -49,8 +52,11 @@ public class PsiCapturedWildcardType extends PsiType.Stub { myExistential = existential; myContext = context; myParameter = parameter; + myUpperBound = PsiType.getJavaLangObject(myContext.getManager(), getResolveScope()); } + private static RecursionGuard guard = RecursionManager.createGuard("captureGuard"); + @Override public boolean equals(Object o) { if (!(o instanceof PsiCapturedWildcardType)) { @@ -58,7 +64,7 @@ public class PsiCapturedWildcardType extends PsiType.Stub { } final PsiCapturedWildcardType captured = (PsiCapturedWildcardType)o; - if (!myContext.equals(captured.myContext) || !myExistential.equals(captured.myExistential)) { + if (!myContext.equals(captured.myContext) || myExistential.isSuper() && !myExistential.equals(captured.myExistential)) { return false; } @@ -66,12 +72,24 @@ public class PsiCapturedWildcardType extends PsiType.Stub { return false; } - return true; + if (myParameter != null) { + final Boolean sameUpperBounds = guard.doPreventingRecursion(myContext, true, new Computable() { + @Override + public Boolean compute() { + return Comparing.equal(myUpperBound, captured.myUpperBound); + } + }); + + if (sameUpperBounds != null && sameUpperBounds) { + return true; + } + } + return myExistential.equals(captured.myExistential); } @Override public int hashCode() { - return myExistential.hashCode() + 31 * myContext.hashCode(); + return myUpperBound.hashCode() + 31 * myContext.hashCode(); } @NotNull @@ -125,14 +143,14 @@ public class PsiCapturedWildcardType extends PsiType.Stub { public PsiType getUpperBound () { final PsiType bound = myExistential.getBound(); - if (myExistential.isExtends()) { + if (myExistential.isExtends() && myParameter == null) { return bound; } else if (bound instanceof PsiCapturedWildcardType) { return PsiWildcardType.createSuper(myContext.getManager(), ((PsiCapturedWildcardType)bound).getUpperBound()); } else { - return myUpperBound != null ? myUpperBound : PsiType.getJavaLangObject(myContext.getManager(), getResolveScope()); + return myUpperBound; } } diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java index 909117c17b14..97be24624827 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java @@ -763,10 +763,11 @@ public final class PsiUtil extends PsiUtilCore { captureContext = captured.getContext(); } PsiType glb = null; + PsiType originalBound = PsiType.NULL; if (substituted instanceof PsiWildcardType) { final PsiType[] boundTypes = typeParameter.getExtendsListTypes(); PsiManager manager = typeParameter.getManager(); - PsiType originalBound = !((PsiWildcardType)substituted).isSuper() ? ((PsiWildcardType)substituted).getBound() : null; + originalBound = !((PsiWildcardType)substituted).isSuper() ? ((PsiWildcardType)substituted).getBound() : null; glb = originalBound; for (PsiType boundType : boundTypes) { PsiType substitutedBoundType = captureSubstitutor.substitute(boundType); @@ -813,9 +814,11 @@ public final class PsiUtil extends PsiUtilCore { if (captureContext != null) { LOG.assertTrue(substituted instanceof PsiWildcardType, substituted); - substituted = oldSubstituted instanceof PsiCapturedWildcardType && substituted.equals(((PsiCapturedWildcardType)oldSubstituted).getWildcard()) - ? oldSubstituted - : PsiCapturedWildcardType.create((PsiWildcardType)substituted, captureContext, typeParameter); + substituted = + oldSubstituted instanceof PsiCapturedWildcardType && substituted.equals(((PsiCapturedWildcardType)oldSubstituted).getWildcard()) + ? oldSubstituted + : captureSubstitutor.substitute(typeParameter); + LOG.assertTrue(substituted instanceof PsiCapturedWildcardType); if (glb != null) { ((PsiCapturedWildcardType)substituted).setUpperBound(glb); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java index 5164ba1623ea..97945bc63dec 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java @@ -257,8 +257,10 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { } else { PsiType substituted = substituteInternal(original); if (original instanceof PsiWildcardType && substituted instanceof PsiCapturedWildcardType) { - substituted = PsiCapturedWildcardType.create(((PsiCapturedWildcardType)substituted).getWildcard(), - ((PsiCapturedWildcardType)substituted).getContext(), param); + final PsiCapturedWildcardType capturedWildcardType = PsiCapturedWildcardType.create(((PsiCapturedWildcardType)substituted).getWildcard(), + ((PsiCapturedWildcardType)substituted).getContext(), param); + capturedWildcardType.setUpperBound(((PsiCapturedWildcardType)substituted).getUpperBound()); + substituted = capturedWildcardType; } //if (substituted == null) return false; substMap.put(param, substituted); diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SimpleMethodReference-out.java b/java/java-tests/testData/codeInsight/completion/smartType/SimpleMethodReference-out.java new file mode 100644 index 000000000000..2d2ee0535d75 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SimpleMethodReference-out.java @@ -0,0 +1,13 @@ +import java.util.List; + +class MyTest { + + void m(List l) { + l.stream().map(Person::getName) + } + +} + +interface Person { + String getName(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SimpleMethodReference.java b/java/java-tests/testData/codeInsight/completion/smartType/SimpleMethodReference.java new file mode 100644 index 000000000000..b654ed02ddb3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SimpleMethodReference.java @@ -0,0 +1,13 @@ +import java.util.List; + +class MyTest { + + void m(List l) { + l.stream().map() + } + +} + +interface Person { + String getName(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/IDEADEV11877.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/IDEADEV11877.java index 39773bd7e428..2d44f189d2e0 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/IDEADEV11877.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/IDEADEV11877.java @@ -16,4 +16,9 @@ class MyCloneable2 { public Object clone() { return null; } +} + +interface MyFinalizable { + @Override void finalize(); + @Override int hashCode(); } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/CapturedBoundOfCapture.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/CapturedBoundOfCapture.java new file mode 100644 index 000000000000..a51689ea9cdb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/CapturedBoundOfCapture.java @@ -0,0 +1,10 @@ + +interface A { + K get(); +} + +class Test { + void f(A a) { + String s = a.get(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA57533.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA57533.java index 0c0628e14aa8..4e37c9763b2e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA57533.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA57533.java @@ -1,6 +1,6 @@ class C>>{ void foo(C x){ - bar(x); + bar(x); } > void bar(C x){} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA67677.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA67677.java index 691a352f8d7d..1c41f96722dd 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA67677.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA67677.java @@ -6,6 +6,6 @@ interface B { class D { void bar(B x, List y) { - x.foo(y); + x.foo(y); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV14006.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV14006.java index f73206bd35cb..1efc6d8ca930 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV14006.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV14006.java @@ -13,6 +13,6 @@ class Test2 {} class Test { public void test(TestIF testIF) { - testIF.run(); + testIF.run(); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV15534.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV15534.java index 4365e40ad1c3..bf1f2d907681 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV15534.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV15534.java @@ -19,7 +19,7 @@ class SortTest> implements Comparable> { SortTest t2 = new SortTest(0); list.add(t2); Collections.sort(list); - t1.compareTo(t2); + t1.compareTo(t2); //this should be OK SortTest[] arr = new SortTest[0]; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57533.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57533.java index d7ffd7e49641..476897f1e9e4 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57533.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57533.java @@ -1,6 +1,6 @@ class C>>{ void foo(C x){ - bar(x); + bar(x); } > void bar(C x){} } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67677.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67677.java index 7f206bbee52b..e62d31a5113b 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67677.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67677.java @@ -6,6 +6,6 @@ interface B { class D { void bar(B x, List y) { - x.foo(y); + x.foo(y); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14006.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14006.java index 77cf1dbfaea8..502e323be476 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14006.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14006.java @@ -13,6 +13,6 @@ class Test2 {} class Test { public void test(TestIF testIF) { - testIF.run(); + testIF.run(); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV15534.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV15534.java index acc225a324cc..5039a4225286 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV15534.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV15534.java @@ -19,7 +19,7 @@ class SortTest> implements Comparable> { SortTest t2 = new SortTest(0); list.add(t2); Collections.sort(list); - t1.compareTo(t2); + t1.compareTo(t2); //this should be OK SortTest[] arr = new SortTest[0]; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java index 68aba5eca978..7b9422407253 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java @@ -123,6 +123,10 @@ public class SmartType18CompletionTest extends LightFixtureCompletionTestCase { doTest(false); } + public void testSimpleMethodReference() throws Exception { + doTest(true); + } + private void doTest() { doTest(true); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java index 29a47dbc8e14..a6104dc70901 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java @@ -508,6 +508,10 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); } + public void testCapturedBoundOfCapture() throws Exception { + doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); + } + public void testJavaUtilCollections_NoVerify() throws Exception { PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule())); assertNotNull(collectionsClass); diff --git a/java/java-tests/testSrc/com/intellij/psi/MiscPsiTest.java b/java/java-tests/testSrc/com/intellij/psi/MiscPsiTest.java index d9f367d85efe..aa8a3c692896 100644 --- a/java/java-tests/testSrc/com/intellij/psi/MiscPsiTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/MiscPsiTest.java @@ -78,6 +78,11 @@ public class MiscPsiTest extends LightCodeInsightFixtureTestCase { PsiFile fileCopy = (PsiFile)file.copy(); fileCopy = (PsiFile) fileCopy.setName("NewTest.xxx"); PsiFile newFile = (PsiFile)dir.add(fileCopy); + if (!(newFile instanceof PsiBinaryFile)) { + System.out.println(newFile.getVirtualFile().getFileType()); + System.out.println(newFile.getFileType()); + System.out.println(newFile.getText()); + } assertInstanceOf(newFile, PsiBinaryFile.class); assertOrderedEquals(newFile.getVirtualFile().contentsToByteArray(), bytes); diff --git a/platform/analysis-api/src/com/intellij/codeInsight/intention/HighPriorityAction.java b/platform/analysis-api/src/com/intellij/codeInsight/intention/HighPriorityAction.java index 938264e38667..d389ec4208d0 100644 --- a/platform/analysis-api/src/com/intellij/codeInsight/intention/HighPriorityAction.java +++ b/platform/analysis-api/src/com/intellij/codeInsight/intention/HighPriorityAction.java @@ -20,7 +20,7 @@ package com.intellij.codeInsight.intention; * Marked actions are shown higher in the list of available quick fixes. * * @author Dmitry Avdeev - * @see com.intellij.codeInsight.intention.IntentionAction + * @see IntentionAction * @see com.intellij.codeInspection.LocalQuickFix */ public interface HighPriorityAction { diff --git a/platform/built-in-server/testSrc/RestApiTest.kt b/platform/built-in-server/testSrc/RestApiTest.kt index 6068a03e1ff1..2f9586857102 100644 --- a/platform/built-in-server/testSrc/RestApiTest.kt +++ b/platform/built-in-server/testSrc/RestApiTest.kt @@ -26,49 +26,49 @@ public class RestApiTest { Rule public fun getChain(): RuleChain = _chain - Test + Test(timeout = 60000) TestDescriptor(filePath = "", status = 400) public fun fileEmptyRequest() { doTest() } - Test + Test(timeout = 60000) TestDescriptor(filePath = "foo.txt", relativeToProject = true, status = 200) public fun relativeToProject() { doTest() } - Test + Test(timeout = 60000) TestDescriptor(filePath = "foo.txt", relativeToProject = true, line = 1, status = 200) public fun relativeToProjectWithLine() { doTest() } - Test + Test(timeout = 60000) TestDescriptor(filePath = "foo.txt", relativeToProject = true, line = 1, column = 13, status = 200) public fun relativeToProjectWithLineAndColumn() { doTest() } - Test + Test(timeout = 60000) TestDescriptor(filePath = "fileInExcludedDir.txt", excluded = true, status = 200) public fun inExcludedDir() { doTest() } - Test + Test(timeout = 60000) TestDescriptor(filePath = "bar/42/foo.txt", doNotCreate = true, status = 404) public fun relativeNonExistent() { doTest() } - Test + Test(timeout = 60000) TestDescriptor(filePath = "_tmp_", doNotCreate = true, status = 404) public fun absoluteNonExistent() { doTest() } - Test + Test(timeout = 60000) TestDescriptor(filePath = "_tmp_", status = 200) public fun absolute() { doTest() diff --git a/platform/core-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java b/platform/core-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java index edb8320db745..bf6acdf11bd8 100644 --- a/platform/core-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java +++ b/platform/core-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java @@ -39,7 +39,7 @@ import java.util.*; import java.util.concurrent.ConcurrentMap; public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends SingleRootFileViewProvider { - private final ConcurrentMap myRoots = ContainerUtil.newConcurrentMap(1, 0.75f, 1); + private final ConcurrentMap myRoots = ContainerUtil.newConcurrentMap(1, 0.75f, 1); private MultiplePsiFilesPerDocumentFileViewProvider myOriginal = null; public MultiplePsiFilesPerDocumentFileViewProvider(PsiManager manager, VirtualFile virtualFile, boolean eventSystemEnabled) { @@ -67,12 +67,15 @@ public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends Single } protected void removeFile(final Language language) { - myRoots.remove(language); + PsiFileImpl file = myRoots.remove(language); + if (file != null) { + file.markInvalidated(); + } } @Override protected PsiFile getPsiInner(@NotNull final Language target) { - PsiFile file = myRoots.get(target); + PsiFileImpl file = myRoots.get(target); if (file == null) { if (isPhysical()) { VirtualFile virtualFile = getVirtualFile(); @@ -85,12 +88,12 @@ public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends Single if (target != getBaseLanguage() && !getLanguages().contains(target)) { return null; } - file = createFile(target); + file = (PsiFileImpl)createFile(target); if (file == null) return null; if (myOriginal != null) { final PsiFile originalFile = myOriginal.getPsi(target); if (originalFile != null) { - ((PsiFileImpl)file).setOriginalFile(originalFile); + file.setOriginalFile(originalFile); } } file = ConcurrencyUtil.cacheOrGet(myRoots, target, file); @@ -120,7 +123,7 @@ public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends Single @TestOnly public void checkAllTreesEqual() { - Collection roots = myRoots.values(); + Collection roots = myRoots.values(); PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getManager().getProject()); documentManager.commitAllDocuments(); for (PsiFile root : roots) { @@ -187,11 +190,21 @@ public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends Single public void contentsSynchronized() { super.contentsSynchronized(); Set languages = getLanguages(); - for (Iterator> iterator = myRoots.entrySet().iterator(); iterator.hasNext(); ) { - Map.Entry entry = iterator.next(); + for (Iterator> iterator = myRoots.entrySet().iterator(); iterator.hasNext(); ) { + Map.Entry entry = iterator.next(); if (!languages.contains(entry.getKey())) { + PsiFileImpl file = entry.getValue(); iterator.remove(); + file.markInvalidated(); } } } + + @Override + public void markInvalidated() { + for (PsiFileImpl file : myRoots.values()) { + file.markInvalidated(); + } + super.markInvalidated(); + } } diff --git a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java index c59facb32dd7..9e27eaff8d94 100644 --- a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java +++ b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java @@ -161,6 +161,9 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi psiFile = createFile(); boolean set = myPsiFile.compareAndSet(null, psiFile); if (!set) { + if (psiFile instanceof PsiFileImpl) { + ((PsiFileImpl)psiFile).markInvalidated(); + } psiFile = myPsiFile.get(); } } @@ -304,6 +307,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi return contentSize > PersistentFSConstants.getMaxIntellisenseFileSize(); } + @SuppressWarnings("UnusedParameters") public static boolean isTooLargeForContentLoading(@NotNull VirtualFile vFile, final long contentSize) { return contentSize > PersistentFSConstants.FILE_LENGTH_TO_CACHE_THRESHOLD; } @@ -446,7 +450,10 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi } public void forceCachedPsi(@NotNull PsiFile psiFile) { - myPsiFile.set(psiFile); + PsiFile prev = myPsiFile.getAndSet(psiFile); + if (prev != psiFile && prev instanceof PsiFileImpl) { + ((PsiFileImpl)prev).markInvalidated(); + } ((PsiManagerEx)myManager).getFileManager().setViewProvider(getVirtualFile(), this); } @@ -476,6 +483,13 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi return getClass().getSimpleName() + "{myVirtualFile=" + myVirtualFile + ", content=" + getContent() + '}'; } + public void markInvalidated() { + PsiFile psiFile = myPsiFile.get(); + if (psiFile instanceof PsiFileImpl) { + ((PsiFileImpl)psiFile).markInvalidated(); + } + } + private interface Content { CharSequence getText(); diff --git a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java index 05d7c4a7523b..73306d3a08e7 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java @@ -131,6 +131,7 @@ public class FileManagerImpl implements FileManager { private void checkLanguageChange() { Map fileToPsiFileMap = new THashMap(myVFileToViewProviderMap); + Map originalFileToPsiFileMap = new THashMap(myVFileToViewProviderMap); myVFileToViewProviderMap.clear(); for (Iterator iterator = fileToPsiFileMap.keySet().iterator(); iterator.hasNext();) { VirtualFile vFile = iterator.next(); @@ -140,6 +141,7 @@ public class FileManagerImpl implements FileManager { } } myVFileToViewProviderMap.putAll(fileToPsiFileMap); + markInvalidations(originalFileToPsiFileMap); } public void forceReload(@NotNull VirtualFile vFile) { @@ -175,15 +177,25 @@ public class FileManagerImpl implements FileManager { myConnection.disconnect(); } ApplicationManager.getApplication().assertWriteAccessAllowed(); + clearViewProviders(); + myDisposed = true; } + private void clearViewProviders() { + for (final FileViewProvider provider : myVFileToViewProviderMap.values()) { + if (provider instanceof SingleRootFileViewProvider) { + ((SingleRootFileViewProvider)provider).markInvalidated(); + } + } + myVFileToViewProviderMap.clear(); + } + @Override @TestOnly public void cleanupForNextTest() { - myVFileToViewProviderMap.clear(); + clearViewProviders(); myVFileToPsiDirMap.clear(); - processQueue(); ((PsiModificationTrackerImpl)myManager.getModificationTracker()).incCounter(); } @@ -222,9 +234,11 @@ public class FileManagerImpl implements FileManager { @Override public void setViewProvider(@NotNull final VirtualFile virtualFile, @Nullable final FileViewProvider fileViewProvider) { FileViewProvider prev = findCachedViewProvider(virtualFile); + if (prev == fileViewProvider) return; if (prev != null) { DebugUtil.startPsiModification(null); try { + ((SingleRootFileViewProvider)prev).markInvalidated(); DebugUtil.onInvalidated(prev); } finally { @@ -450,7 +464,10 @@ public class FileManagerImpl implements FileManager { myVFileToPsiDirMap.remove(file); } else { - myVFileToViewProviderMap.remove(file); + FileViewProvider viewProvider = myVFileToViewProviderMap.remove(file); + if (viewProvider instanceof SingleRootFileViewProvider) { + ((SingleRootFileViewProvider)viewProvider).markInvalidated(); + } } return true; } @@ -499,6 +516,7 @@ public class FileManagerImpl implements FileManager { // note: important to update directories map first - findFile uses findDirectory! Map fileToPsiFileMap = new THashMap(myVFileToViewProviderMap); + Map originalFileToPsiFileMap = new THashMap(myVFileToViewProviderMap); if (useFind) { myVFileToViewProviderMap.clear(); } @@ -535,6 +553,17 @@ public class FileManagerImpl implements FileManager { } myVFileToViewProviderMap.clear(); myVFileToViewProviderMap.putAll(fileToPsiFileMap); + + markInvalidations(originalFileToPsiFileMap); + } + + private void markInvalidations(Map originalFileToPsiFileMap) { + for (Map.Entry entry : originalFileToPsiFileMap.entrySet()) { + FileViewProvider viewProvider = entry.getValue(); + if (viewProvider instanceof SingleRootFileViewProvider && myVFileToViewProviderMap.get(entry.getKey()) != viewProvider) { + ((SingleRootFileViewProvider)viewProvider).markInvalidated(); + } + } } @Override diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index 9b90b02d7e6c..f6e67bf8202b 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -71,6 +71,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF protected PsiFile myOriginalFile = null; private final FileViewProvider myViewProvider; private volatile Reference myStub; + private boolean myInvalidated; protected final PsiManagerEx myManager; private volatile Getter myTreeElementPointer; // SoftReference/WeakReference to ASTNode or a strong reference to a tree if the file is a DummyHolder public static final Key BUILDING_STUB = new Key("Don't use stubs mark!"); @@ -147,22 +148,21 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF @Override public boolean isValid() { - FileViewProvider provider = getViewProvider(); - final VirtualFile vFile = provider.getVirtualFile(); - if (!vFile.isValid()) return false; - if (!provider.isEventSystemEnabled()) return true; // "dummy" file - if (myManager.getProject().isDisposed()) return false; - return isPsiUpToDate(vFile); + if (myManager.getProject().isDisposed()) { + // normally FileManager.dispose would call markInvalidated + // but there's temporary disposed project in tests, which doesn't actually dispose its components :( + return false; + } + if (!myViewProvider.getVirtualFile().isValid()) { + // PSI listeners receive VFS deletion events and do markInvalidated + // but some VFS listeners receive the same events before that and ask PsiFile.isValid + return false; + } + return !myInvalidated; } - protected boolean isPsiUpToDate(@NotNull VirtualFile vFile) { - final FileViewProvider provider = myManager.findViewProvider(vFile); - Language language = getLanguage(); - if (provider == null || provider.getPsi(language) == this) { // provider == null in tests - return true; - } - Language baseLanguage = provider.getBaseLanguage(); - return baseLanguage != language && provider.getPsi(baseLanguage) == this; + public void markInvalidated() { + myInvalidated = true; } @Override @@ -711,7 +711,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF } @Override - public PsiManager getManager() { + public final PsiManager getManager() { return myManager; } @@ -929,11 +929,8 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF @Override @NotNull - public Project getProject() { - final PsiManager manager = getManager(); - if (manager == null) throw new PsiInvalidElementAccessException(this); - - return manager.getProject(); + public final Project getProject() { + return getManager().getProject(); } @NotNull diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/PsiReferenceRegistrarImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/PsiReferenceRegistrarImpl.java index bcea41fd6ceb..5baae80ead23 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/PsiReferenceRegistrarImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/PsiReferenceRegistrarImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source.resolve.reference; +import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.patterns.*; @@ -24,43 +25,53 @@ import com.intellij.psi.PsiReferenceRegistrar; import com.intellij.psi.PsiReferenceService; import com.intellij.util.ArrayUtil; import com.intellij.util.ProcessingContext; -import com.intellij.util.SmartList; import com.intellij.util.containers.ConcurrentFactoryMap; -import com.intellij.util.containers.FactoryMap; -import gnu.trove.THashMap; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; /** * @author Dmitry Avdeev */ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.resolve.reference.PsiReferenceRegistrarImpl"); - private final Map> myBindingsMap = new THashMap>(); - private final Map> myNamedBindingsMap = new THashMap>(); - private final FactoryMap myKnownSupers = new ConcurrentFactoryMap() { - @Override - protected Class[] create(Class key) { - final Set result = new LinkedHashSet(); - for (Class candidate : myBindingsMap.keySet()) { - if (candidate.isAssignableFrom(key)) { - result.add(candidate); - } - } - for (Class candidate : myNamedBindingsMap.keySet()) { - if (candidate.isAssignableFrom(key)) { - result.add(candidate); - } - } - if (result.isEmpty()) { - return ArrayUtil.EMPTY_CLASS_ARRAY; - } - return result.toArray(new Class[result.size()]); - } - }; + private final Map, SimpleProviderBinding> myBindingsMap = ContainerUtil.newTroveMap(); + private final Map, NamedObjectProviderBinding> myNamedBindingsMap = ContainerUtil.newTroveMap(); + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + private final ConcurrentFactoryMap[]> myBindingCache; private boolean myInitialized; + public PsiReferenceRegistrarImpl(final Language language) { + myBindingCache = new ConcurrentFactoryMap[]>() { + @Nullable + @Override + protected ProviderBinding[] create(Class key) { + List> result = ContainerUtil.newSmartList(); + for (Class bindingClass : myBindingsMap.keySet()) { + if (bindingClass.isAssignableFrom(key)) { + result.add(myBindingsMap.get(bindingClass)); + } + } + for (Class bindingClass : myNamedBindingsMap.keySet()) { + if (bindingClass.isAssignableFrom(key)) { + result.add(myNamedBindingsMap.get(bindingClass)); + } + } + if (language != Language.ANY) { + final PsiReferenceRegistrar anyRegistrar = ReferenceProvidersRegistry.getInstance().getRegistrar(Language.ANY); + Collections.addAll(result, ((PsiReferenceRegistrarImpl)anyRegistrar).myBindingCache.get(key)); + } + //noinspection unchecked + return result.toArray(new ProviderBinding[result.size()]); + } + }; + } + public void markInitialized() { myInitialized = true; } @@ -73,7 +84,6 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar { LOG.error("Reference provider registration is only allowed from PsiReferenceContributor"); } - myKnownSupers.clear(); // we should clear the cache final Class scope = pattern.getCondition().getInitialCondition().getAcceptedClass(); final List> conditions = pattern.getCondition().getConditions(); for (PatternCondition _condition : conditions) { @@ -102,6 +112,8 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar { myBindingsMap.put(scope, providerBinding = new SimpleProviderBinding()); } providerBinding.registerProvider(provider, pattern, priority); + + myBindingCache.clear(); } public void unregisterReferenceProvider(@NotNull Class scope, @NotNull PsiReferenceProvider provider) { @@ -141,22 +153,14 @@ public class PsiReferenceRegistrarImpl extends PsiReferenceRegistrar { @NotNull List> getPairsByElement(@NotNull PsiElement element, @NotNull PsiReferenceService.Hints hints) { - final Class clazz = element.getClass(); - List> ret = null; - for (Class aClass : myKnownSupers.get(clazz)) { - SimpleProviderBinding simpleBinding = myBindingsMap.get(aClass); - NamedObjectProviderBinding namedBinding = myNamedBindingsMap.get(aClass); - if (simpleBinding == null && namedBinding == null) continue; + final ProviderBinding[] bindings = myBindingCache.get(element.getClass()); + if (bindings.length == 0) return Collections.emptyList(); - if (ret == null) ret = new SmartList>(); - if (simpleBinding != null) { - simpleBinding.addAcceptableReferenceProviders(element, ret, hints); - } - if (namedBinding != null) { - namedBinding.addAcceptableReferenceProviders(element, ret, hints); - } + List> ret = ContainerUtil.newSmartList(); + for (ProviderBinding binding : bindings) { + binding.addAcceptableReferenceProviders(element, ret, hints); } - return ret == null ? Collections.>emptyList() : ret; + return ret; } } diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java index 39b584f6a1ef..9e858844de4d 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java @@ -20,7 +20,6 @@ import com.intellij.lang.Language; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.psi.*; -import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; @@ -48,7 +47,7 @@ public abstract class ReferenceProvidersRegistry { public abstract PsiReferenceRegistrar getRegistrar(@NotNull Language language); /** - * @see #getReferencesFromProviders(com.intellij.psi.PsiElement) + * @see #getReferencesFromProviders(PsiElement) */ @Deprecated @NotNull @@ -64,10 +63,7 @@ public abstract class ReferenceProvidersRegistry { @NotNull public static PsiReference[] getReferencesFromProviders(@NotNull PsiElement context, @NotNull PsiReferenceService.Hints hints) { ProgressIndicatorProvider.checkCanceled(); - PsiUtilCore.ensureValid(context); - - ReferenceProvidersRegistry registry = getInstance(); - return registry.doGetReferencesFromProviders(context, hints); + return getInstance().doGetReferencesFromProviders(context, hints); } @NotNull diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistryImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistryImpl.java index 6d913a0ba816..9078c6539f65 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistryImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistryImpl.java @@ -23,7 +23,6 @@ import com.intellij.patterns.ElementPattern; import com.intellij.psi.*; import com.intellij.util.ProcessingContext; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.FactoryMap; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -41,82 +40,79 @@ public class ReferenceProvidersRegistryImpl extends ReferenceProvidersRegistry { } }; - @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"}) - private final Map myRegistrars = new FactoryMap() { - @Override - protected PsiReferenceRegistrarImpl create(Language language) { - PsiReferenceRegistrarImpl registrar = new PsiReferenceRegistrarImpl(); - for (PsiReferenceContributor contributor : CONTRIBUTOR_EXTENSION.allForLanguage(language)) { - contributor.registerReferenceProviders(registrar); - } + private final Map myRegistrars = ContainerUtil.newConcurrentMap(); - List referenceProviderBeans = REFERENCE_PROVIDER_EXTENSION.allForLanguage(language); - for (final PsiReferenceProviderBean providerBean : referenceProviderBeans) { - final ElementPattern pattern = providerBean.createElementPattern(); - if (pattern != null) { - registrar.registerReferenceProvider(pattern, new PsiReferenceProvider() { - - PsiReferenceProvider myProvider; - - @NotNull - @Override - public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { - if (myProvider == null) { - - myProvider = providerBean.instantiate(); - if (myProvider == null) { - myProvider = NULL_REFERENCE_PROVIDER; - } - } - return myProvider.getReferencesByElement(element, context); - } - }); - } - } - - registrar.markInitialized(); - - return registrar; + @NotNull + private static PsiReferenceRegistrarImpl createRegistrar(Language language) { + PsiReferenceRegistrarImpl registrar = new PsiReferenceRegistrarImpl(language); + for (PsiReferenceContributor contributor : CONTRIBUTOR_EXTENSION.allForLanguage(language)) { + contributor.registerReferenceProviders(registrar); } - }; + + List referenceProviderBeans = REFERENCE_PROVIDER_EXTENSION.allForLanguage(language); + for (final PsiReferenceProviderBean providerBean : referenceProviderBeans) { + final ElementPattern pattern = providerBean.createElementPattern(); + if (pattern != null) { + registrar.registerReferenceProvider(pattern, new PsiReferenceProvider() { + + PsiReferenceProvider myProvider; + + @NotNull + @Override + public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { + if (myProvider == null) { + + myProvider = providerBean.instantiate(); + if (myProvider == null) { + myProvider = NULL_REFERENCE_PROVIDER; + } + } + return myProvider.getReferencesByElement(element, context); + } + }); + } + } + + registrar.markInitialized(); + + return registrar; + } + @NotNull @Override - public synchronized PsiReferenceRegistrarImpl getRegistrar(@NotNull Language language) { - return myRegistrars.get(language); + public PsiReferenceRegistrarImpl getRegistrar(@NotNull Language language) { + PsiReferenceRegistrarImpl registrar = myRegistrars.get(language); + if (registrar == null) { + //noinspection SynchronizeOnThis + synchronized (this) { + registrar = myRegistrars.get(language); + if (registrar == null) { + myRegistrars.put(language, registrar = createRegistrar(language)); + } + } + } + return registrar; } @NotNull @Override protected PsiReference[] doGetReferencesFromProviders(@NotNull PsiElement context, @NotNull PsiReferenceService.Hints hints) { - List> providersForContextLanguage = - getRegistrar(context.getLanguage()).getPairsByElement(context, hints); + List> providers = getRegistrar(context.getLanguage()).getPairsByElement(context, hints); - List> providersForAllLanguages = - getRegistrar(Language.ANY).getPairsByElement(context, hints); - - int providersCount = providersForContextLanguage.size() + providersForAllLanguages.size(); - - if (providersCount == 0) { + if (providers.isEmpty()) { return PsiReference.EMPTY_ARRAY; } - if (providersCount == 1) { - final ProviderBinding.ProviderInfo firstProvider = - (providersForAllLanguages.isEmpty() ? providersForContextLanguage : providersForAllLanguages).get(0); - return firstProvider.provider.getReferencesByElement(context, firstProvider.processingContext); + if (providers.size() == 1) { + return providers.get(0).provider.getReferencesByElement(context, providers.get(0).processingContext); } - List> list = - ContainerUtil.concat(providersForContextLanguage, providersForAllLanguages); - @SuppressWarnings("unchecked") - ProviderBinding.ProviderInfo[] providers = list.toArray(new ProviderBinding.ProviderInfo[list.size()]); - - Arrays.sort(providers, PRIORITY_COMPARATOR); + ContainerUtil.sort(providers, PRIORITY_COMPARATOR); List result = new ArrayList(); - final double maxPriority = providers[0].priority; + final double maxPriority = providers.get(0).priority; next: for (ProviderBinding.ProviderInfo trinity : providers) { final PsiReference[] refs; diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java index 6d3826e6863a..f772d6820d60 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java @@ -97,8 +97,8 @@ public class UISettings extends SimpleModificationTracker implements PersistentS public boolean ACTIVATE_RIGHT_EDITOR_ON_CLOSE = false; @Deprecated public boolean ANTIALIASING_IN_EDITOR = true; - public boolean ANTIALIASING_IN_IDE = !UIUtil.isRetina() && ANTIALIASING_IN_EDITOR; - public LCDRenderingScope LCD_RENDERING_SCOPE = LCDRenderingScope.IDE; + public boolean ANTIALIASING_IN_IDE = ANTIALIASING_IN_EDITOR; + public LCDRenderingScope LCD_RENDERING_SCOPE = UIUtil.isRetina() ? LCDRenderingScope.OFF : LCDRenderingScope.IDE; public boolean USE_LCD_RENDERING_IN_EDITOR = true; public boolean MOVE_MOUSE_ON_DEFAULT_BUTTON = false; public boolean ENABLE_ALPHA_MODE = false; diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/Caret.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/Caret.java index 1ca3f7bac418..f467e246395b 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/Caret.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/Caret.java @@ -302,4 +302,11 @@ public interface Caret extends UserDataHolderEx, Disposable { * to offset and logical column number in the vicinity of caret. */ boolean isAtRtlLocation(); + + /** + * Returns true if caret is located at a boundary between LTR and RTL text fragments. Caret can located at any side of the + * boundary, exact location can be determined from directionality flags of caret's logical and visual position + * ({@link LogicalPosition#leansForward} and {@link VisualPosition#leansRight}). + */ + boolean isAtDirectionBoundary(); } diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/VisualPosition.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/VisualPosition.java index 633d85678b18..62f541df208c 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/VisualPosition.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/VisualPosition.java @@ -77,6 +77,13 @@ public class VisualPosition { return line > other.line; } + /** + * Constructs a new VisualPosition instance with a given value of {@link #leansRight} flag. + */ + public VisualPosition leanRight(boolean value) { + return new VisualPosition(line, column, value); + } + @NonNls public String toString() { return "VisualPosition: (" + line + ", " + column+")" + (leansRight ? " leans right" : ""); 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 93712c209b99..84deb1b8a118 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 @@ -94,22 +94,30 @@ public class LiftShorterItemsClassifier extends Classifier { } private void internListToLift(LookupElement longer) { - myToLift.put(longer, myListInterner.intern(myToLift.get(longer))); + final Collection elements = myToLift.get(longer); + if (elements.size() > 10) return; + + myToLift.put(longer, myListInterner.intern(elements)); } private void calculateToLift(LookupElement element) { boolean hasChanges = false; - for (String string : element.getAllLookupStrings()) { - for (int len = 1; len < string.length(); len++) { - String prefix = string.substring(0, len); - for (LookupElement shorterElement : myElements.get(prefix)) { - if (myCondition.shouldLift(shorterElement, element)) { - hasChanges = true; - myToLift.putValue(element, shorterElement); + try { + for (String string : element.getAllLookupStrings()) { + for (int len = 1; len < string.length(); len++) { + String prefix = string.substring(0, len); + for (LookupElement shorterElement : myElements.get(prefix)) { + if (myCondition.shouldLift(shorterElement, element)) { + hasChanges = true; + myToLift.putValue(element, shorterElement); + } } } } } + catch (ConcurrentModificationException e) { + throw new RuntimeException("Error while traversing lookup strings of " + element + " of " + element.getClass(), e); + } if (hasChanges) { internListToLift(element); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GutterIntentionAction.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GutterIntentionAction.java new file mode 100644 index 000000000000..39e4551d9298 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/GutterIntentionAction.java @@ -0,0 +1,118 @@ +/* + * 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.daemon.impl; + +import com.intellij.codeInsight.intention.AbstractIntentionAction; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.ex.RangeHighlighterEx; +import com.intellij.openapi.editor.markup.GutterIconRenderer; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.psi.PsiFile; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.Collections; +import java.util.List; + +/** + * @author Dmitry Avdeev + */ +class GutterIntentionAction extends AbstractIntentionAction implements Comparable { + private final AnAction myAction; + private final EditorEx myEditor; + private final String myText; + + public GutterIntentionAction(AnAction action, String text, EditorEx editor) { + myAction = action; + myEditor = editor; + myText = text; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final RelativePoint relativePoint = JBPopupFactory.getInstance().guessBestPopupLocation(editor); + myAction.actionPerformed( + new AnActionEvent(relativePoint.toMouseEvent(), myEditor.getDataContext(), myText, new Presentation(), + ActionManager.getInstance(), 0)); + } + + @Override + @NotNull + public String getText() { + return myText; + } + + static void addActions(RangeHighlighterEx info, + EditorEx editor, + List descriptors) { + final GutterIconRenderer renderer = info.getGutterIconRenderer(); + if (renderer == null) { + return; + } + addActions(renderer.getClickAction(), editor, descriptors, renderer); + addActions(renderer.getMiddleButtonClickAction(), editor, descriptors, renderer); + addActions(renderer.getRightButtonClickAction(), editor, descriptors, renderer); + addActions(renderer.getPopupMenuActions(), editor, descriptors, renderer); + } + + private static void addActions(AnAction action, + EditorEx editor, + List descriptors, + GutterIconRenderer renderer) { + if (action == null) { + return; + } + if (action instanceof ActionGroup) { + AnAction[] children = ((ActionGroup)action).getChildren(null); + for (AnAction child : children) { + addActions(child, editor, descriptors, renderer); + } + } + AnActionEvent event = AnActionEvent.createFromDataContext(ActionPlaces.UNKNOWN, null, editor.getDataContext()); + action.update(event); + String text = event.getPresentation().getText(); + if (text == null) text = action.getTemplatePresentation().getText(); + if (text == null) { + return; + } + final IntentionAction actionAdapter = new GutterIntentionAction(action, text, editor); + Icon icon = action.getTemplatePresentation().getIcon(); + if (icon == null) icon = renderer.getIcon(); + HighlightInfo.IntentionActionDescriptor descriptor = + new HighlightInfo.IntentionActionDescriptor(actionAdapter, Collections.emptyList(), text, icon); + descriptors.add(descriptor); + } + + @Override + public int compareTo(IntentionAction o) { + if (o instanceof GutterIntentionAction) { + AnAction other = ((GutterIntentionAction)o).myAction; + if (myAction instanceof Comparable) { + return ((Comparable)myAction).compareTo(other); + } + else if (other instanceof Comparable) { + return -((Comparable)other).compareTo(myAction); + } + } + return 0; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java index 4ec78e19ff83..f50d95b524b4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java @@ -19,7 +19,6 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeHighlighting.TextEditorHighlightingPass; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.hint.HintManager; -import com.intellij.codeInsight.intention.AbstractIntentionAction; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.IntentionManager; import com.intellij.codeInsight.intention.impl.IntentionHintComponent; @@ -28,12 +27,7 @@ import com.intellij.codeInsight.intention.impl.config.IntentionManagerSettings; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.codeInspection.actions.CleanupAllIntention; -import com.intellij.ide.DataManager; import com.intellij.lang.annotation.HighlightSeverity; -import com.intellij.openapi.actionSystem.ActionManager; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -41,11 +35,12 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.ex.EditorEx; -import com.intellij.openapi.editor.markup.GutterIconRenderer; +import com.intellij.openapi.editor.ex.MarkupModelEx; +import com.intellij.openapi.editor.ex.RangeHighlighterEx; +import com.intellij.openapi.editor.impl.DocumentMarkupModel; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; import com.intellij.psi.IntentionFilterOwner; @@ -53,8 +48,6 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; -import com.intellij.ui.awt.RelativePoint; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.PairProcessor; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; @@ -63,7 +56,6 @@ import org.jetbrains.annotations.NotNull; import java.awt.*; import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -315,43 +307,15 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass { } final int line = hostDocument.getLineNumber(offset); - DaemonCodeAnalyzerEx.processHighlights(hostDocument, project, null, - hostDocument.getLineStartOffset(line), - hostDocument.getLineEndOffset(line), new Processor() { - @Override - public boolean process(HighlightInfo info) { - final GutterIconRenderer renderer = (GutterIconRenderer)info.getGutterIconRenderer(); - if (renderer == null) { + MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(hostDocument, project, true); + model.processRangeHighlightersOverlappingWith(hostDocument.getLineStartOffset(line), + hostDocument.getLineEndOffset(line), new Processor() { + @Override + public boolean process(RangeHighlighterEx highlighter) { + GutterIntentionAction.addActions(highlighter, (EditorEx)hostEditor, intentions.guttersToShow); return true; } - final AnAction action = renderer.getClickAction(); - if (action == null) { - return true; - } - final String text = renderer.getTooltipText(); - if (text == null) { - return true; - } - final IntentionAction actionAdapter = new AbstractIntentionAction() { - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - final RelativePoint relativePoint = JBPopupFactory.getInstance().guessBestPopupLocation(editor); - action.actionPerformed( - new AnActionEvent(relativePoint.toMouseEvent(), DataManager.getInstance().getDataContext(), text, new Presentation(), - ActionManager.getInstance(), 0)); - } - - @Override - @NotNull - public String getText() { - return text; - } - }; - intentions.guttersToShow.add( - new HighlightInfo.IntentionActionDescriptor(actionAdapter, Collections.emptyList(), text, renderer.getIcon())); - return true; - } - }); + }); boolean cleanup = appendCleanupCode(intentions.inspectionFixesToShow, hostFile); if (!cleanup) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionListStep.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionListStep.java index 83da606987c4..f9717dda2df0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionListStep.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/IntentionListStep.java @@ -36,7 +36,6 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.*; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Iconable; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; @@ -310,7 +309,7 @@ class IntentionListStep implements ListPopupStep if (weight1 != weight2) { return weight2 - weight1; } - return Comparing.compare(o1.getText(), o2.getText()); + return o1.compareTo(o2); } }); return result; @@ -355,6 +354,9 @@ class IntentionListStep implements ListPopupStep if (myCachedInspectionFixes.contains(action)) { return 10; } + if (myCachedGutters.contains(action)) { + return 5; + } if (action.getAction() instanceof EmptyIntentionAction) { return -10; } diff --git a/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerInfo.java b/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerInfo.java index 89c303c344de..c46132a2c258 100644 --- a/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerInfo.java +++ b/platform/lang-impl/src/com/intellij/execution/lineMarker/RunLineMarkerInfo.java @@ -19,24 +19,16 @@ import com.intellij.codeHighlighting.Pass; import com.intellij.codeInsight.daemon.LineMarkerInfo; import com.intellij.execution.Executor; import com.intellij.execution.ExecutorRegistry; -import com.intellij.execution.Location; -import com.intellij.execution.PsiLocation; -import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.actionSystem.impl.ActionPopupMenuImpl; import com.intellij.openapi.editor.markup.GutterIconRenderer; -import com.intellij.openapi.util.Getter; -import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.psi.PsiElement; import com.intellij.util.Function; import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; @@ -60,67 +52,35 @@ public class RunLineMarkerInfo extends LineMarkerInfo { return true; } + @NotNull + @Override + public ActionGroup getPopupMenuActions() { + List actions = new ArrayList(); + Executor[] executors = ExecutorRegistry.getInstance().getRegisteredExecutors(); + actions.addAll(ContainerUtil.mapNotNull(executors, + new Function() { + @Override + public AnAction fun(Executor executor) { + return ActionManager.getInstance().getAction(executor.getContextActionId()); + } + })); + actions.add(Separator.getInstance()); + actions.addAll(ContainerUtil.mapNotNull(RunLineMarkerContributor.EXTENSION.allForLanguage(myElement.getLanguage()), + new NullableFunction() { + @Nullable + @Override + public AnAction fun(RunLineMarkerContributor contributor) { + return contributor.getAdditionalAction(myElement); + } + })); + + return new DefaultActionGroup(actions); + } + @Override public AnAction getClickAction() { - return new AnAction() { - @Override - public void actionPerformed(AnActionEvent e) { - List actions = new ArrayList(); - Executor[] executors = ExecutorRegistry.getInstance().getRegisteredExecutors(); - actions.addAll(ContainerUtil.mapNotNull(executors, - new Function() { - @Override - public AnAction fun(Executor executor) { - return ActionManager.getInstance().getAction(executor.getContextActionId()); - } - })); - actions.add(Separator.getInstance()); - actions.addAll(ContainerUtil.mapNotNull(RunLineMarkerContributor.EXTENSION.allForLanguage(myElement.getLanguage()), - new NullableFunction() { - @Nullable - @Override - public AnAction fun(RunLineMarkerContributor contributor) { - return contributor.getAdditionalAction(myElement); - } - })); - - ActionPopupMenuImpl - popupMenu = (ActionPopupMenuImpl)ActionManager.getInstance().createActionPopupMenu(ActionPlaces.EDITOR_POPUP, - new DefaultActionGroup(actions)); - final MouseEvent me = (MouseEvent)e.getInputEvent(); - final Component c = me.getComponent(); - if (c != null && c.isShowing()) { - final DataContext delegate = DataManager.getInstance().getDataContext(c, me.getX(), me.getY()); - final DataContext dataContext = new MyDataContext(myElement, delegate); - popupMenu.setDataContextProvider(new Getter() { - @Override - public DataContext get() { - return dataContext; - } - }); - popupMenu.getComponent().show(c, me.getX(), me.getY()); - } - } - }; + return null; } }; } - - private static class MyDataContext extends UserDataHolderBase implements DataContext { - private final PsiElement myElement; - private final DataContext myDelegate; - - public MyDataContext(PsiElement element, DataContext delegate) { - myElement = element; - myDelegate = delegate; - } - - @Nullable - @Override - public Object getData(@NonNls String dataId) { - if (Location.DATA_KEY.is(dataId)) return new PsiLocation(myElement); - return myDelegate.getData(dataId); - } - } - } 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 1d99f6b8b598..f51c068a312a 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -1761,6 +1761,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } } + } else { + classes.add(o); } return true; } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewModuleNode.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewModuleNode.java index 8c8446faf432..a6fbc89ef64c 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewModuleNode.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewModuleNode.java @@ -18,7 +18,6 @@ package com.intellij.ide.projectView.impl.nodes; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.util.treeView.AbstractTreeNode; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleFileIndex; @@ -35,16 +34,11 @@ import java.util.Collections; import java.util.List; public class ProjectViewModuleNode extends AbstractModuleNode { - private static final Logger LOG = Logger.getInstance("#com.intellij.ide.projectView.impl.nodes.ProjectViewModuleNode"); public ProjectViewModuleNode(Project project, Module value, ViewSettings viewSettings) { super(project, value, viewSettings); } - public ProjectViewModuleNode(Project project, Object value, ViewSettings viewSettings) { - this(project, (Module)value, viewSettings); - } - @Override @NotNull public Collection getChildren() { diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index c3f304baf028..8bea1a3318fe 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -275,9 +275,14 @@ public abstract class ChooseByNameBase { @Override public Object getData(String dataId) { + if (PlatformDataKeys.SEARCH_INPUT_TEXT.is(dataId)) { + return myTextField == null ? null : myTextField.getText(); + } + if (PlatformDataKeys.HELP_ID.is(dataId)) { return myModel.getHelpId(); } + if (myCalcElementsThread != null) { return null; } diff --git a/platform/lang-impl/src/com/intellij/injected/editor/InjectedCaret.java b/platform/lang-impl/src/com/intellij/injected/editor/InjectedCaret.java index 508a9bee4f8e..468745cabb59 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/InjectedCaret.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/InjectedCaret.java @@ -242,4 +242,9 @@ public class InjectedCaret implements Caret { public boolean isAtRtlLocation() { return myDelegate.isAtRtlLocation(); } + + @Override + public boolean isAtDirectionBoundary() { + return myDelegate.isAtDirectionBoundary(); + } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java index f32043c2d2c5..f9d8e5d93f80 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java @@ -566,7 +566,7 @@ public class PsiVFSListener extends VirtualFileAdapter { if (oldElement.getClass().equals(newElement.getClass())) { treeEvent.setOldParent(oldParentDir); treeEvent.setNewParent(newParentDir); - treeEvent.setChild(newElement); + treeEvent.setChild(oldElement); myManager.childMoved(treeEvent); } else { diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java index 1bccc8ed66ac..0c679463a134 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java @@ -197,19 +197,15 @@ public abstract class ChangeSignatureDialogBase extends PopupStep { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/MoveCaretLeftOrRightHandler.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/MoveCaretLeftOrRightHandler.java index be2628f6741c..6edbe7a679c4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/MoveCaretLeftOrRightHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/MoveCaretLeftOrRightHandler.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. @@ -69,8 +69,14 @@ class MoveCaretLeftOrRightHandler extends EditorActionHandler { } } } - final boolean scrollToCaret = (!(editor instanceof EditorImpl) || ((EditorImpl)editor).isScrollToCaret()) - && caret == editor.getCaretModel().getPrimaryCaret(); - caretModel.moveCaretRelatively(myDirection == Direction.RIGHT ? 1 : -1, 0, false, false, scrollToCaret); + VisualPosition currentPosition = caret.getVisualPosition(); + if (caret.isAtDirectionBoundary() && (myDirection == Direction.RIGHT ^ currentPosition.leansRight)) { + caret.moveToVisualPosition(currentPosition.leanRight(!currentPosition.leansRight)); + } + else { + final boolean scrollToCaret = (!(editor instanceof EditorImpl) || ((EditorImpl)editor).isScrollToCaret()) + && caret == editor.getCaretModel().getPrimaryCaret(); + caretModel.moveCaretRelatively(myDirection == Direction.RIGHT ? 1 : -1, 0, false, false, scrollToCaret); + } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java index 1bab16ab8981..59cd0b94b504 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java @@ -267,6 +267,8 @@ public class CaretImpl extends UserDataHolderBase implements Caret { int newLineNumber = visualCaret.line + lineShift; int newColumnNumber = visualCaret.column + columnShift; + boolean newLeansRight = lineShift == 0 && columnShift != 0 ? columnShift < 0 : visualCaret.leansRight; + if (desiredX >= 0) { newColumnNumber = myEditor.xyToVisualPosition(new Point(desiredX, Math.max(0, newLineNumber) * myEditor.getLineHeight())).column; } @@ -305,13 +307,14 @@ public class CaretImpl extends UserDataHolderBase implements Caret { VisualPosition pos = new VisualPosition(newLineNumber, newColumnNumber); if (!myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) { - LogicalPosition log = myEditor.visualToLogicalPosition(new VisualPosition(newLineNumber, newColumnNumber)); + LogicalPosition log = myEditor.visualToLogicalPosition(new VisualPosition(newLineNumber, newColumnNumber, newLeansRight)); int offset = myEditor.logicalPositionToOffset(log); if (offset >= document.getTextLength()) { - int lastOffsetColumn = myEditor.offsetToVisualPosition(document.getTextLength()).column; + int lastOffsetColumn = myEditor.offsetToVisualPosition(document.getTextLength(), true).column; // We want to move caret to the last column if if it's located at the last line and 'Down' is pressed. if (lastOffsetColumn > newColumnNumber) { newColumnNumber = lastOffsetColumn; + newLeansRight = true; desiredX = -1; lastColumnNumber = -1; } @@ -321,7 +324,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret { if (offset >= 0 && offset < document.getTextLength()) { if (text.charAt(offset) == '\t' && (columnShift <= 0 || offset == myOffset)) { if (columnShift <= 0) { - newColumnNumber = myEditor.offsetToVisualPosition(offset).column; + newColumnNumber = myEditor.offsetToVisualPosition(offset, true).column; } else { SoftWrap softWrap = myEditor.getSoftWrapModel().getSoftWrap(offset + 1); @@ -339,7 +342,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret { } } - pos = new VisualPosition(newLineNumber, newColumnNumber); + pos = new VisualPosition(newLineNumber, newColumnNumber, newLeansRight); if (columnShift != 0 && lineShift == 0 && myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) { LogicalPosition logical = myEditor.visualToLogicalPosition(pos); int softWrapOffset = myEditor.logicalPositionToOffset(logical); @@ -1466,6 +1469,11 @@ public class CaretImpl extends UserDataHolderBase implements Caret { return myEditor.myUseNewRendering && myEditor.myView.isRtlLocation(myOffset, myLogicalCaret.leansForward); } + @Override + public boolean isAtDirectionBoundary() { + return myEditor.myUseNewRendering && myEditor.myView.isDirectionBoundary(myOffset); + } + /** * Encapsulates information about target vertical range info - its 'y' coordinate and height in pixels. */ diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java index c6d567927861..6830e9470974 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java @@ -102,7 +102,7 @@ public class ContextMenuImpl extends JPanel implements Disposable { final Rectangle r = viewport.getBounds(); final Point viewPosition = viewport.getViewPosition(); - final Rectangle activationArea = new Rectangle(0, 0, r.width, 150); + final Rectangle activationArea = new Rectangle(0, 0, r.width, r.height); return activationArea.contains(p.x, p.y - viewPosition.y); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index f74db8116375..aaa7c9d7b7b7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -1354,13 +1354,18 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse @Override public void mousePressed(MouseEvent e) { - if (e.isPopupTrigger()) { + if (e.isPopupTrigger() || isPopupAction(e)) { invokePopup(e); } else if (UIUtil.isCloseClick(e)) { processClose(e); } } + private boolean isPopupAction(MouseEvent e) { + GutterIconRenderer renderer = getGutterRenderer(e); + return renderer != null && renderer.getClickAction() == null && renderer.getPopupMenuActions() != null; + } + @Override public void mouseReleased(final MouseEvent e) { if (e.isPopupTrigger()) { 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 d32326e4333b..d3d63440f01e 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 @@ -304,7 +304,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi private CaretImpl myPrimaryCaret; - private final boolean myDisableRtl = Registry.is("editor.disable.rtl"); + public final boolean myDisableRtl = Registry.is("editor.disable.rtl"); public final boolean myUseNewRendering = Registry.is("editor.new.rendering"); final EditorView myView; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java index 9e623c20b882..b900ee5be8b4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java @@ -656,9 +656,9 @@ class EditorPainter { g.fillRect(x, y, lineWidth, lineHeight); if (myDocument.getTextLength() > 0 && caret != null && !myView.getLineLayout(caret.getLogicalPosition().line).isLtr()) { g.fillPolygon(new int[]{ - isRtl ? x + lineWidth - 1 : x, - isRtl ? x + lineWidth - 1 - CARET_DIRECTION_MARK_SIZE : x + CARET_DIRECTION_MARK_SIZE, - isRtl ? x + lineWidth - 1 : x + isRtl ? x + lineWidth : x, + isRtl ? x + lineWidth - CARET_DIRECTION_MARK_SIZE : x + CARET_DIRECTION_MARK_SIZE, + isRtl ? x + lineWidth : x }, new int[]{y, y, y + CARET_DIRECTION_MARK_SIZE}, 3); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java index 79f44decbb5b..de7cdeea888a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorView.java @@ -268,6 +268,14 @@ public class EditorView implements Disposable { return layout.isRtlLocation(offset - myDocument.getLineStartOffset(line), leanForward); } + public boolean isDirectionBoundary(int offset) { + assertIsDispatchThread(); + if (myDocument.getTextLength() == 0) return false; + int line = myDocument.getLineNumber(offset); + LineLayout layout = getLineLayout(line); + return layout.isDirectionBoundary(offset - myDocument.getLineStartOffset(line)); + } + @NotNull LineLayout getLineLayout(int line) { return myTextLayoutCache.getLineLayout(line); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java index 7260caae957b..9f55f2e82e18 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java @@ -18,7 +18,6 @@ package com.intellij.openapi.editor.impl.view; import com.intellij.openapi.editor.colors.FontPreferences; import com.intellij.openapi.editor.impl.ComplementaryFontsRegistry; import com.intellij.openapi.editor.impl.EditorImpl; -import com.intellij.openapi.util.registry.Registry; import com.intellij.util.text.CharArrayUtil; import org.intellij.lang.annotations.JdkConstants; import org.jetbrains.annotations.NotNull; @@ -81,7 +80,7 @@ class LineLayout { EditorImpl editor = view.getEditor(); FontPreferences fontPreferences = editor.getColorsScheme().getFontPreferences(); char[] chars = CharArrayUtil.fromSequence(editor.getDocument().getImmutableCharSequence(), lineStartOffset, lineEndOffset); - List runs = createRuns(chars); + List runs = createRuns(editor, chars); for (BidiRun run : runs) { IterationState it = new IterationState(editor, lineStartOffset + run.startOffset, lineStartOffset + run.endOffset, false, false, false, false); @@ -101,7 +100,7 @@ class LineLayout { EditorImpl editor = view.getEditor(); FontPreferences fontPreferences = editor.getColorsScheme().getFontPreferences(); char[] chars = CharArrayUtil.fromSequence(text); - List runs = createRuns(chars); + List runs = createRuns(editor, chars); for (BidiRun run : runs) { addFragments(run, chars, run.startOffset, run.endOffset, fontStyle, fontPreferences, fontRenderContext, null); assert !run.fragments.isEmpty(); @@ -109,8 +108,8 @@ class LineLayout { return runs; } - private static List createRuns(char[] text) { - if (Registry.is("editor.disable.rtl")) return Collections.singletonList(new BidiRun((byte)0, 0, text.length)); + private static List createRuns(EditorImpl editor, char[] text) { + if (editor.myDisableRtl) return Collections.singletonList(new BidiRun((byte)0, 0, text.length)); Bidi bidi = new Bidi(text, 0, null, 0, text.length, Bidi.DIRECTION_LEFT_TO_RIGHT); int runCount = bidi.getRunCount(); List runs = new ArrayList(runCount); @@ -212,6 +211,17 @@ class LineLayout { return false; } + boolean isDirectionBoundary(int offset) { + boolean prevIsRtl = false; + for (BidiRun run : myBidiRunsInLogicalOrder) { + boolean curIsRtl = run.isRtl(); + if (offset == run.startOffset && curIsRtl != prevIsRtl) return true; + if (offset < run.endOffset) return false; + prevIsRtl = curIsRtl; + } + return prevIsRtl; + } + private static class BidiRun { private final byte level; private final int startOffset; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaret.java b/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaret.java index bce02d483344..482694255f8f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaret.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaret.java @@ -203,6 +203,11 @@ public class TextComponentCaret extends UserDataHolderBase implements Caret { return false; } + @Override + public boolean isAtDirectionBoundary() { + return false; + } + private SelectionModel getSelectionModel() { return myEditor.getSelectionModel(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java index 1e35bff23812..11f95e896a60 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java @@ -231,7 +231,7 @@ public class VfsImplUtil { public void run() { LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); } - }, ModalityState.defaultModalityState()); + }, ModalityState.NON_MODAL); } @SuppressWarnings("unchecked") T t = (T)handler; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java index 8b4ee27aedb3..5c13920a2772 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java @@ -120,7 +120,8 @@ public class VfsData { if (o == ourDeadMarker) { throw reportDeadFileAccess(new VirtualFileImpl(id, segment, parent)); } - assert segment.getNameId(id) > 0; + final int nameId = segment.getNameId(id); + assert nameId > 0 : "nameId=" + nameId + "; data=" + o + "; parent=" + parent; return o instanceof DirectoryData ? new VirtualDirectoryImpl(id, segment, (DirectoryData)o, parent, parent.getFileSystem()) : new VirtualFileImpl(id, segment, parent); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index 661bf1f0cdf9..b8319cecc401 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -99,7 +99,9 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { if (result == null) { synchronized (myData) { - addToAdoptedChildren(ignoreCase, name); + if (!allChildrenLoaded()) { + myData.addAdoptedName(name, getFileSystem().isCaseSensitive()); + } } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java index 0d773e4a94c0..28878e749fe1 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorRtlTest.java @@ -235,6 +235,29 @@ public class EditorRtlTest extends AbstractEditorTest { assertLogicalPositionsEqual("Wrong logical position", lF(1), myEditor.getCaretModel().getLogicalPosition()); } + public void testNavigationWithArrowKeys() throws Exception { + init("llrrll\nllrrll"); + assertCaretPosition(vL(0)); + right(); + assertCaretPosition(vL(1)); + right(); + assertCaretPosition(vL(2)); + right(); + assertCaretPosition(vR(2)); + right(); + assertCaretPosition(vL(3)); + right(); + assertCaretPosition(vL(4)); + down(); + assertCaretPosition(v(1, 4, false)); + left(); + assertCaretPosition(v(1, 3, true)); + left(); + assertCaretPosition(v(1, 2, true)); + up(); + assertCaretPosition(vR(2)); + } + private void init(String text) throws IOException { initText(text.replace(RTL_CHAR_REPRESENTATION, RTL_CHAR)); } @@ -299,6 +322,10 @@ public class EditorRtlTest extends AbstractEditorTest { assertEquals(message, expectedPosition, actualPosition); assertEquals(message + " (direction flag)", expectedPosition.leansRight, actualPosition.leansRight); } + + private static void assertCaretPosition(VisualPosition visualPosition) { + assertVisualPositionsEqual("Wrong caret position", visualPosition, myEditor.getCaretModel().getVisualPosition()); + } // logical position leaning backward private static LogicalPosition lB(int column) { diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java index 1caaee7a1c99..776684a8bcca 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java @@ -574,6 +574,22 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest executeAction("EditorSelectLine"); } + protected static void left() { + executeAction("EditorLeft"); + } + + protected static void right() { + executeAction("EditorRight"); + } + + protected static void up() { + executeAction("EditorUp"); + } + + protected static void down() { + executeAction("EditorDown"); + } + protected static void lineComment() { new CommentByLineCommentAction().actionPerformedImpl(getProject(), getEditor()); } diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 5cf788334808..1c40ba022199 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -2085,6 +2085,15 @@ public class UIUtil { return new Color(actual.getRed(), actual.getGreen(), actual.getBlue(), alpha); } + /** + * @param component to check whether it can be focused or not + * @return {@code true} if component is not {@code null} and can be focused + * @see Component#isRequestFocusAccepted(boolean, boolean, sun.awt.CausedFocusEvent.Cause) + */ + public static boolean isFocusable(JComponent component) { + return component != null && component.isFocusable() && component.isEnabled() && component.isShowing(); + } + public static void requestFocus(@NotNull final JComponent c) { if (c.isShowing()) { c.requestFocus(); diff --git a/platform/vcs-api/src/com/intellij/vcsUtil/VcsSelectionUtil.java b/platform/vcs-api/src/com/intellij/vcsUtil/VcsSelectionUtil.java index 88c5631c50f0..136178faf2b3 100644 --- a/platform/vcs-api/src/com/intellij/vcsUtil/VcsSelectionUtil.java +++ b/platform/vcs-api/src/com/intellij/vcsUtil/VcsSelectionUtil.java @@ -18,6 +18,7 @@ package com.intellij.vcsUtil; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.vcs.actions.VcsContext; import org.jetbrains.annotations.Nullable; @@ -35,10 +36,13 @@ public class VcsSelectionUtil { if (selectionFromEditor != null) { return selectionFromEditor; } - final VcsSelectionProvider[] providers = Extensions.getExtensions(VcsSelectionProvider.EP_NAME); - for(VcsSelectionProvider provider: providers) { - final VcsSelection vcsSelection = provider.getSelection(context); - if (vcsSelection != null) return vcsSelection; + for(VcsSelectionProvider provider: Extensions.getExtensions(VcsSelectionProvider.EP_NAME)) { + try { + final VcsSelection vcsSelection = provider.getSelection(context); + if (vcsSelection != null) return vcsSelection; + } + catch (IndexNotReadyException ignored) { + } } return null; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java index d0d5aaabeeac..dc638dc682fd 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java @@ -27,6 +27,7 @@ import com.intellij.ui.ColoredTextContainer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.NotNullFunction; import com.intellij.util.ThreeState; +import com.intellij.util.ui.tree.TreeUtil; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.frame.*; @@ -124,6 +125,10 @@ public class XValueNodeImpl extends XValueContainerNode implements XValu @Override public void applyPresentation(@Nullable Icon icon, @NotNull XValuePresentation valuePresentation, boolean hasChildren) { + // extra check for obsolete nodes - tree root was changed + // too dangerous to put this into isObsolete - it is called from anywhere, not only EDT + if (isObsolete() || !TreeUtil.isAncestor(getTree().getRoot(), this)) return; + setIcon(icon); myValuePresentation = valuePresentation; myRawValue = XValuePresentationUtil.computeValueText(valuePresentation); diff --git a/plugins/devkit/src/testAssistant/GotoTestDataAction.java b/plugins/devkit/src/testAssistant/GotoTestDataAction.java index fdc56a12aab3..5201e1f4d673 100644 --- a/plugins/devkit/src/testAssistant/GotoTestDataAction.java +++ b/plugins/devkit/src/testAssistant/GotoTestDataAction.java @@ -18,18 +18,21 @@ package org.jetbrains.idea.devkit.testAssistant; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ui.FilePathSplittingPolicy; import java.io.File; -class GotoTestDataAction extends AnAction { +class GotoTestDataAction extends AnAction implements Comparable { private final String myBasePath; private final Project myProject; public GotoTestDataAction(String basePath, Project project) { - super(basePath); + super("Go to " + FilePathSplittingPolicy.SPLIT_BY_SEPARATOR.getPresentableName(new File(basePath), 50), null, + FileTypeManager.getInstance().getFileTypeByFileName(basePath).getIcon()); myBasePath = basePath; myProject = project; } @@ -41,4 +44,9 @@ class GotoTestDataAction extends AnAction { new OpenFileDescriptor(myProject, baseDir).navigate(true); } } + + @Override + public int compareTo(Object o) { + return o instanceof GotoTestDataAction ? 0 : 1; + } } diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitRunLineMarkerProvider.java b/plugins/junit/src/com/intellij/execution/junit/JUnitRunLineMarkerProvider.java index 794e843a90c3..f49c3c4995a7 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnitRunLineMarkerProvider.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnitRunLineMarkerProvider.java @@ -22,6 +22,7 @@ import com.intellij.execution.lineMarker.RunLineMarkerInfo; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; +import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,13 +33,21 @@ import java.util.List; * @author Dmitry Avdeev */ public class JUnitRunLineMarkerProvider implements LineMarkerProvider { + + private static final Function TOOLTIP_PROVIDER = new Function() { + @Override + public String fun(PsiElement element) { + return "Run Test"; + } + }; + @Nullable @Override public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) { if (element instanceof PsiClass && JUnitUtil.isTestClass((PsiClass)element, false, true)) - return new RunLineMarkerInfo(element, JUnitConfigurationType.getInstance().getIcon(), null); + return new RunLineMarkerInfo(element, JUnitConfigurationType.getInstance().getIcon(), TOOLTIP_PROVIDER); if (element instanceof PsiMethod && JUnitUtil.isTestMethod(new PsiLocation((PsiMethod)element))) - return new RunLineMarkerInfo(element, JUnitConfigurationType.getInstance().getIcon(), null); + return new RunLineMarkerInfo(element, JUnitConfigurationType.getInstance().getIcon(), TOOLTIP_PROVIDER); return null; } diff --git a/plugins/testng_rt/src/org/testng/IDEATestNGRemoteListener.java b/plugins/testng_rt/src/org/testng/IDEATestNGRemoteListener.java index 75a12befc1ab..d05de93caffe 100644 --- a/plugins/testng_rt/src/org/testng/IDEATestNGRemoteListener.java +++ b/plugins/testng_rt/src/org/testng/IDEATestNGRemoteListener.java @@ -127,11 +127,8 @@ public class IDEATestNGRemoteListener implements ISuiteListener, IResultListener for (int i = idx; i < parentsHierarchy.size(); i++) { String fqName = parentsHierarchy.get(parentsHierarchy.size() - 1 - i); String currentClassName = getShortName(fqName); - myPrintStream.print("\n##teamcity[testSuiteStarted name =\'" + escapeName(currentClassName)); - if (provideLocation) { - myPrintStream.print("\' locationHint = \'java:suite://" + escapeName(fqName)); - } - myPrintStream.println("\']"); + myPrintStream.println("\n##teamcity[testSuiteStarted name =\'" + escapeName(currentClassName) + + (provideLocation ? "\' locationHint = \'java:suite://" + escapeName(fqName) : "") + "\']"); myCurrentSuites.add(currentClassName); } return false; diff --git a/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsForm.form b/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsForm.form index 127610fca739..f4c489166faf 100644 --- a/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsForm.form +++ b/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsForm.form @@ -57,7 +57,7 @@ - + diff --git a/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java b/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java index 164264988635..4249e2b271e9 100644 --- a/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/completion/XmlAttributeInsertHandler.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight.completion; +import com.intellij.application.options.editor.WebEditorOptions; import com.intellij.codeInsight.AutoPopupController; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.diagnostic.Logger; @@ -65,14 +66,18 @@ public class XmlAttributeInsertHandler implements InsertHandler { final PsiFile file = context.getFile(); final CharSequence chars = document.getCharsSequence(); - if (!CharArrayUtil.regionMatches(chars, caretOffset, "=\"") && !CharArrayUtil.regionMatches(chars, caretOffset, "='")) { + final boolean insertQuotes = WebEditorOptions.getInstance().isInsertQuotesForAttributeValue(); + final boolean hasQuotes = CharArrayUtil.regionMatches(chars, caretOffset, "=\""); + if (!hasQuotes && !CharArrayUtil.regionMatches(chars, caretOffset, "='")) { PsiElement fileContext = file.getContext(); String toInsert= "=\"\""; if(fileContext != null) { if (fileContext.getText().startsWith("\"")) toInsert = "=''"; } - + + if (!insertQuotes) toInsert = "="; + if (caretOffset >= document.getTextLength() || "/> \n\t\r".indexOf(document.getCharsSequence().charAt(caretOffset)) < 0) { document.insertString(caretOffset, toInsert + " "); } @@ -85,7 +90,7 @@ public class XmlAttributeInsertHandler implements InsertHandler { } } - editor.getCaretModel().moveToOffset(caretOffset + 2); + editor.getCaretModel().moveToOffset(caretOffset + (insertQuotes || hasQuotes ? 2 : 1)); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); editor.getSelectionModel().removeSelection(); AutoPopupController.getInstance(editor.getProject()).scheduleAutoPopup(editor); diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java index 169195d2bbdf..d1e5a5f44de7 100644 --- a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java @@ -50,7 +50,13 @@ public class XmlEqTypedHandler extends TypedHandlerDelegate { public Result charTyped(char c, Project project, @NotNull Editor editor, @NotNull PsiFile file) { if (needToInsertQuotes) { int offset = editor.getCaretModel().getOffset(); - editor.getDocument().insertString(offset, "\"\""); + PsiElement fileContext = file.getContext(); + String toInsert= "\"\""; + + if(fileContext != null) { + if (fileContext.getText().startsWith("\"")) toInsert = "''"; + } + editor.getDocument().insertString(offset, toInsert); editor.getCaretModel().moveToOffset(offset + 1); AutoPopupController.getInstance(project).scheduleAutoPopup(editor); } diff --git a/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java b/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java index bb831e5fec88..65852e6eb1c0 100644 --- a/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java +++ b/xml/tests/src/com/intellij/codeInsight/completion/XmlCompletionTest.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight.completion; +import com.intellij.application.options.editor.WebEditorOptions; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; import com.intellij.codeInsight.lookup.Lookup; @@ -348,6 +349,18 @@ public class XmlCompletionTest extends LightCodeInsightFixtureTestCase { checkResultByFile(getTestName(true) + ".xml"); } + public void testAttributeNoQuotes() throws Throwable { + boolean oldInsertQuotes = WebEditorOptions.getInstance().isInsertQuotesForAttributeValue(); + WebEditorOptions.getInstance().setInsertQuotesForAttributeValue(false); + try { + configureByFile(getTestName(false) + ".xml"); + selectItem(myFixture.getLookupElements()[0], '\t'); + checkResultByFile(getTestName(false) + "_after.xml"); + } finally { + WebEditorOptions.getInstance().setInsertQuotesForAttributeValue(oldInsertQuotes); + } + } + public void testBeforeAttributeNameWithPrefix() throws Exception { configureByFile(getTestName(true) + ".xml"); selectItem(myFixture.getLookupElements()[0], '\t'); diff --git a/xml/tests/testData/completion/AttributeNoQuotes.xml b/xml/tests/testData/completion/AttributeNoQuotes.xml new file mode 100644 index 000000000000..177a400bd07f --- /dev/null +++ b/xml/tests/testData/completion/AttributeNoQuotes.xml @@ -0,0 +1,5 @@ + + + /> + + \ No newline at end of file diff --git a/xml/tests/testData/completion/AttributeNoQuotes_after.xml b/xml/tests/testData/completion/AttributeNoQuotes_after.xml new file mode 100644 index 000000000000..7ce6792363ac --- /dev/null +++ b/xml/tests/testData/completion/AttributeNoQuotes_after.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/dtd/HtmlElementDescriptorImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/dtd/HtmlElementDescriptorImpl.java index aec421651439..969129e22022 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/dtd/HtmlElementDescriptorImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/html/dtd/HtmlElementDescriptorImpl.java @@ -17,6 +17,7 @@ package com.intellij.psi.impl.source.html.dtd; import com.intellij.html.impl.RelaxedHtmlFromSchemaElementDescriptor; import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.XmlTag; import com.intellij.xml.XmlAttributeDescriptor; import com.intellij.xml.XmlElementDescriptor; @@ -70,6 +71,30 @@ public class HtmlElementDescriptorImpl extends BaseXmlElementDescriptorImpl { if (!myCaseSensitive) name = name.toLowerCase(); XmlElementDescriptor xmlElementDescriptor = getElementDescriptor(name, element); + if (xmlElementDescriptor == null && "html".equals(getName())) { + XmlTag head = null; + XmlTag body = null; + + for (XmlTag child : PsiTreeUtil.getChildrenOfTypeAsList(contextTag, XmlTag.class)) { + if ("head".equals(child.getName())) head = child; + if ("body".equals(child.getName())) body = child; + } + if (head == null) { + if (body == null || element.getTextOffset() < body.getTextOffset()) { + XmlElementDescriptor headDescriptor = getElementDescriptor("head", contextTag); + if (headDescriptor != null) { + xmlElementDescriptor = headDescriptor.getElementDescriptor(element, contextTag); + } + } + } + if (xmlElementDescriptor == null && body == null) { + XmlElementDescriptor bodyDescriptor = getElementDescriptor("body", contextTag); + if (bodyDescriptor != null) { + xmlElementDescriptor = bodyDescriptor.getElementDescriptor(element, contextTag); + } + } + + } if (xmlElementDescriptor == null && myRelaxed) { xmlElementDescriptor = RelaxedHtmlFromSchemaElementDescriptor.getRelaxedDescriptor(this, element); }