diff --git a/images/src/org/intellij/images/ui/ImageComponentUI.java b/images/src/org/intellij/images/ui/ImageComponentUI.java index d4c1f466ff8b..366d521235ff 100644 --- a/images/src/org/intellij/images/ui/ImageComponentUI.java +++ b/images/src/org/intellij/images/ui/ImageComponentUI.java @@ -118,7 +118,7 @@ public class ImageComponentUI extends ComponentUI { g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); } - UIUtil.drawImage(g, renderer, 0, 0, size.width, size.height, ic); + UIUtil.drawImage(g, renderer, new Rectangle(0, 0, size.width, size.height), null, ic); g2d.setRenderingHints(oldHints); } diff --git a/java/java-analysis-impl/src/com/intellij/psi/impl/search/JavaNullMethodArgumentUtil.java b/java/java-analysis-impl/src/com/intellij/psi/impl/search/JavaNullMethodArgumentUtil.java index ca9bee749750..25d5751511f7 100644 --- a/java/java-analysis-impl/src/com/intellij/psi/impl/search/JavaNullMethodArgumentUtil.java +++ b/java/java-analysis-impl/src/com/intellij/psi/impl/search/JavaNullMethodArgumentUtil.java @@ -15,12 +15,14 @@ */ package com.intellij.psi.impl.search; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScopeUtil; import com.intellij.psi.search.GlobalSearchScopesCore; import com.intellij.psi.search.searches.MethodReferencesSearch; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; import com.intellij.util.indexing.FileBasedIndex; @@ -32,6 +34,7 @@ import java.util.Collection; import java.util.Collections; public class JavaNullMethodArgumentUtil { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.search.JavaNullMethodArgumentUtil"); public static boolean hasNullArgument(@NotNull PsiMethod method, final int argumentIdx) { final boolean[] result = {false}; @@ -47,35 +50,55 @@ public class JavaNullMethodArgumentUtil { if (parameter.getType() instanceof PsiEllipsisType) { return; } - final GlobalSearchScope scope = findScopeWhereNullArgumentCanPass(method, argumentIdx); - if (scope == null) return; + Collection candidateFiles = getFilesWithPotentialNullPassingCalls(method, argumentIdx); + + long start = System.currentTimeMillis(); + + processCallsWithNullArguments(method, argumentIdx, nullArgumentProcessor, candidateFiles); + + long duration = System.currentTimeMillis() - start; + if (duration > 200) { + LOG.trace("Long nullable argument search for " + method.getName() + "(" + PsiUtil.getMemberQualifiedName(method) + "): " + duration + "ms, " + candidateFiles.size() + " files"); + } + } + + private static void processCallsWithNullArguments(@NotNull PsiMethod method, + int argumentIdx, + @NotNull Processor nullArgumentProcessor, + Collection candidateFiles) { + if (candidateFiles.isEmpty()) return; + + GlobalSearchScope scope = GlobalSearchScope.filesScope(method.getProject(), candidateFiles); MethodReferencesSearch.search(method, scope, true).forEach(ref -> { - final PsiElement psi = ref.getElement(); - if (psi != null) { - final PsiElement parent = psi.getParent(); - PsiExpressionList argumentList = null; - if (parent instanceof PsiCallExpression) { - argumentList = ((PsiCallExpression)parent).getArgumentList(); - } - else if (parent instanceof PsiAnonymousClass) { - argumentList = ((PsiAnonymousClass)parent).getArgumentList(); - } - if (argumentList != null) { - final PsiExpression[] arguments = argumentList.getExpressions(); - if (argumentIdx < arguments.length) { - final PsiExpression argument = arguments[argumentIdx]; - if (argument instanceof PsiLiteralExpression && PsiKeyword.NULL.equals(argument.getText())) { - return nullArgumentProcessor.process(argument); - } - } - } + PsiExpression argument = getCallArgument(ref, argumentIdx); + if (argument instanceof PsiLiteralExpression && argument.textMatches(PsiKeyword.NULL)) { + return nullArgumentProcessor.process(argument); } return true; }); } @Nullable - private static GlobalSearchScope findScopeWhereNullArgumentCanPass(@NotNull PsiMethod method, int parameterIndex) { + private static PsiExpression getCallArgument(PsiReference ref, int argumentIdx) { + PsiExpressionList argumentList = getCallArgumentList(ref.getElement()); + PsiExpression[] arguments = argumentList == null ? PsiExpression.EMPTY_ARRAY : argumentList.getExpressions(); + return argumentIdx < arguments.length ? arguments[argumentIdx] : null; + } + + @Nullable + private static PsiExpressionList getCallArgumentList(@Nullable PsiElement psi) { + PsiElement parent = psi == null ? null :psi.getParent(); + if (parent instanceof PsiCallExpression) { + return ((PsiCallExpression)parent).getArgumentList(); + } + else if (parent instanceof PsiAnonymousClass) { + return ((PsiAnonymousClass)parent).getArgumentList(); + } + return null; + } + + @NotNull + private static Collection getFilesWithPotentialNullPassingCalls(@NotNull PsiMethod method, int parameterIndex) { final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance(); final CommonProcessors.CollectProcessor collector = new CommonProcessors.CollectProcessor<>(new ArrayList<>()); GlobalSearchScope searchScope = GlobalSearchScopeUtil.toGlobalSearchScope(method.getUseScope(), method.getProject()); @@ -84,8 +107,6 @@ public class JavaNullMethodArgumentUtil { Collections.singleton(new JavaNullMethodArgumentIndex.MethodCallData(method.getName(), parameterIndex)), collector, searchScope); - final Collection candidateFiles = collector.getResults(); - return candidateFiles.isEmpty() ? null : GlobalSearchScope.filesScope(method.getProject(), candidateFiles); + return collector.getResults(); } - } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index eff31fe313f0..7aa276fa0fc3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -462,15 +462,14 @@ public class JavaCompletionUtil { }), -1); } if (containsMember(qualifierType, object)) { - LookupElementRenderer> boldRenderer = - new LookupElementRenderer>() { - @Override - public void renderElement(LookupElementDecorator element, LookupElementPresentation presentation) { - element.getDelegate().renderElement(presentation); - presentation.setItemTextBold(true); - } - }; - return PrioritizedLookupElement.withExplicitProximity(LookupElementDecorator.withRenderer(item, boldRenderer), 1); + LookupElementDecorator bold = LookupElementDecorator.withRenderer(item, new LookupElementRenderer>() { + @Override + public void renderElement(LookupElementDecorator element, LookupElementPresentation presentation) { + element.getDelegate().renderElement(presentation); + presentation.setItemTextBold(true); + } + }); + return object instanceof PsiField ? bold : PrioritizedLookupElement.withExplicitProximity(bold, 1); } return item; } @@ -885,7 +884,9 @@ public class JavaCompletionUtil { String open = escapeXmlIfNeeded(context, "<"); context.getDocument().insertString(offset, open); context.getEditor().getCaretModel().moveToOffset(offset + open.length()); - context.getDocument().insertString(offset + open.length(), escapeXmlIfNeeded(context, ">")); + if (CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) { + context.getDocument().insertString(offset + open.length(), escapeXmlIfNeeded(context, ">")); + } if (context.getCompletionChar() != Lookup.COMPLETE_STATEMENT_SELECT_CHAR) { context.setAddCompletionChar(false); } diff --git a/java/java-tests/testData/codeInsight/completion/normal/PairAngleBracketDisabled.java b/java/java-tests/testData/codeInsight/completion/normal/PairAngleBracketDisabled.java new file mode 100644 index 000000000000..23019ec02ef5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/PairAngleBracketDisabled.java @@ -0,0 +1,6 @@ +public class SomeClass { + private void b() { + List + } +} + diff --git a/java/java-tests/testData/codeInsight/completion/normal/PairAngleBracketDisabled_after.java b/java/java-tests/testData/codeInsight/completion/normal/PairAngleBracketDisabled_after.java new file mode 100644 index 000000000000..b61097e930ea --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/PairAngleBracketDisabled_after.java @@ -0,0 +1,8 @@ +import java.util.List; + +public class SomeClass { + private void b() { + List< + } +} + diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy index 54279fd23e1a..9f23ce123570 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy @@ -111,7 +111,7 @@ class NormalCompletionOrderingTest extends CompletionSortingTestCase { final String path = getTestName(false) + ".java" myFixture.configureByFile(path) myFixture.complete(CompletionType.BASIC, 2) - assertPreferredItems(0, "BOOLEAN", "booleanMethod", "AN_OBJECT", "voidMethod") + assertPreferredItems(0, "booleanMethod", "BOOLEAN", "voidMethod", "AN_OBJECT") } void testDispreferDeclared() throws Throwable { diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy index 78c673e52601..6859eca05c7e 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy @@ -45,7 +45,7 @@ class NormalCompletionTest extends LightFixtureCompletionTestCase { void testSimple() throws Exception { configureByFile("Simple.java") - assertStringItems("_field", "_local1", "_local2", "_baseField", "_method", "_baseMethod") + assertStringItems("_local1", "_local2", "_field", "_baseField", "_method", "_baseMethod") } void testCastToPrimitive1() throws Exception { @@ -222,6 +222,7 @@ class NormalCompletionTest extends LightFixtureCompletionTestCase { protected void tearDown() throws Exception { CodeInsightSettings.instance.AUTOCOMPLETE_ON_CODE_COMPLETION = true CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.FIRST_LETTER + CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET = true super.tearDown() } @@ -361,44 +362,22 @@ class NormalCompletionTest extends LightFixtureCompletionTestCase { } void testMethodWithLeftParTailTypeNoPairBrace() throws Exception { - final boolean old = CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET = false - - try { - configureByFile(getTestName(false) + ".java") - type('(') - checkResult() - } - finally { - CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET = old - } + doTest('(') } void testMethodWithLeftParTailTypeNoPairBrace2() throws Exception { - final boolean old = CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET = false - try { - //no tail type should work the normal way - configureByFile("MethodWithLeftParTailTypeNoPairBrace.java") - selectItem(myItems[0]) - checkResultByFile("MethodWithLeftParTailTypeNoPairBrace_after2.java") - } - finally { - CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET = old - } + //no tail type should work the normal way + configureByFile("MethodWithLeftParTailTypeNoPairBrace.java") + selectItem(myItems[0]) + checkResultByFile("MethodWithLeftParTailTypeNoPairBrace_after2.java") } void testMethodNoPairBrace() throws Exception { - final boolean old = CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET = false - - try { - doTest '\n' - } - finally { - CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET = old - } + doTest '\n' } void testExcessSpaceInTypeCast() throws Throwable { @@ -1784,5 +1763,10 @@ class Bar { myFixture.addClass("package pkg; public class PathUtil { public static String toSystemDependentName() {} }") doTest('\n') } + + void testPairAngleBracketDisabled() { + CodeInsightSettings.instance.AUTOINSERT_PAIR_BRACKET = false + doTest('<') + } } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java index ab6b44d95bb4..a98b1359d683 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java @@ -473,7 +473,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { public void testNoUninitializedFieldsInConstructor() throws Throwable { configureByTestName(); - assertStringItems("aab", "aac", "hashCode"); + assertStringItems("aac", "aab", "hashCode"); } public void testFieldsSetInAnotherConstructor() throws Throwable { doTest(); } public void testFieldsSetAbove() throws Throwable { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/VariablesCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/VariablesCompletionTest.groovy index cb02f1717d68..63d377944e93 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/VariablesCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/VariablesCompletionTest.groovy @@ -56,7 +56,7 @@ class VariablesCompletionTest extends LightFixtureCompletionTestCase { void testLocals2() throws Exception { configureByFile(FILE_PREFIX + "locals/" + "TestSource2.java") - myFixture.assertPreferredCompletionItems 0, 'aaa', 'abc' + myFixture.assertPreferredCompletionItems 0, 'abc', 'aaa' checkResultByFile(FILE_PREFIX + "locals/" + "TestResult2.java") } diff --git a/platform/analysis-api/src/com/intellij/analysis/AnalysisScope.java b/platform/analysis-api/src/com/intellij/analysis/AnalysisScope.java index 40dd7314ae3e..dda78e9f9b96 100644 --- a/platform/analysis-api/src/com/intellij/analysis/AnalysisScope.java +++ b/platform/analysis-api/src/com/intellij/analysis/AnalysisScope.java @@ -278,7 +278,7 @@ public class AnalysisScope { final FileIndex fileIndex = getFileIndex(); accept(file -> { if (file.isDirectory()) return true; - if (ProjectCoreUtil.isProjectOrWorkspaceFile(file, file.getFileType())) return true; + if (ProjectCoreUtil.isProjectOrWorkspaceFile(file)) return true; if (fileIndex.isInContent(file) && !isFiltered(file) && !GeneratedSourcesFilter.isGeneratedSourceByAnyFilter(file, myProject)) { return processFile(file, visitor, psiManager, needReadAction, clearResolveCache); diff --git a/platform/analysis-api/src/com/intellij/psi/search/GlobalSearchScopesCore.java b/platform/analysis-api/src/com/intellij/psi/search/GlobalSearchScopesCore.java index 01e986373567..8d1911331416 100644 --- a/platform/analysis-api/src/com/intellij/psi/search/GlobalSearchScopesCore.java +++ b/platform/analysis-api/src/com/intellij/psi/search/GlobalSearchScopesCore.java @@ -28,12 +28,14 @@ import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.search.scope.packageSet.*; -import com.intellij.util.ArrayUtil; import com.intellij.util.ObjectUtils; -import com.intellij.util.containers.SmartHashSet; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; public class GlobalSearchScopesCore { @NotNull @@ -58,14 +60,12 @@ public class GlobalSearchScopesCore { @NotNull public static GlobalSearchScope directoriesScope(@NotNull Project project, boolean withSubdirectories, @NotNull VirtualFile... directories) { - if (directories.length ==1) { + if (directories.length == 1) { return directoryScope(project, directories[0], withSubdirectories); } - BitSet withSubdirectoriesBS = new BitSet(directories.length); - if (withSubdirectories) { - withSubdirectoriesBS.set(0, directories.length); - } - return new DirectoriesScope(project, directories, withSubdirectoriesBS); + return new DirectoriesScope(project, + withSubdirectories ? Collections.emptySet() : ContainerUtil.newHashSet(directories), + withSubdirectories ? ContainerUtil.newHashSet(directories) : Collections.emptySet()); } public static GlobalSearchScope filterScope(@NotNull Project project, @NotNull NamedScope set) { @@ -220,7 +220,12 @@ public class GlobalSearchScopesCore { @Override public boolean contains(@NotNull VirtualFile file) { - return myWithSubdirectories ? VfsUtilCore.isAncestor(myDirectory, file, false) : myDirectory.equals(file.getParent()); + VirtualFile parent = file.getParent(); + return parent != null && in(parent); + } + + private boolean in(@NotNull VirtualFile parent) { + return myWithSubdirectories ? VfsUtilCore.isAncestor(myDirectory, parent, false) : myDirectory.equals(parent); } @Override @@ -262,17 +267,22 @@ public class GlobalSearchScopesCore { if (equals(scope)) return this; if (scope instanceof DirectoryScope) { DirectoryScope other = (DirectoryScope)scope; - VirtualFile otherDirectory = other.myDirectory; - if (myWithSubdirectories && VfsUtilCore.isAncestor(myDirectory, otherDirectory, false)) return this; - if (other.myWithSubdirectories && VfsUtilCore.isAncestor(otherDirectory, myDirectory, false)) return other; - BitSet newWithSubdirectories = new BitSet(); - newWithSubdirectories.set(0, myWithSubdirectories); - newWithSubdirectories.set(1, other.myWithSubdirectories); - return new DirectoriesScope(getProject(), new VirtualFile[]{myDirectory,otherDirectory}, newWithSubdirectories); + if (in(other.myDirectory)) return this; + if (other.in(myDirectory)) return other; + return new DirectoriesScope(getProject(), + union(!myWithSubdirectories, myDirectory, !other.myWithSubdirectories, other.myDirectory), + union(myWithSubdirectories, myDirectory, other.myWithSubdirectories, other.myDirectory)); } return super.uniteWith(scope); } + private static Set union(boolean addDir1, @NotNull VirtualFile dir1, boolean addDir2, @NotNull VirtualFile dir2) { + if (addDir1 && addDir2) return ContainerUtil.newHashSet(dir1, dir2); + if (addDir1) return Collections.singleton(dir1); + if (addDir2) return Collections.singleton(dir2); + return Collections.emptySet(); + } + @NotNull @Override public Project getProject() { @@ -288,15 +298,18 @@ public class GlobalSearchScopesCore { } static class DirectoriesScope extends GlobalSearchScope { - private final VirtualFile[] myDirectories; - private final BitSet myWithSubdirectories; + private final Set myDirectories; + private final Set myDirectoriesWithSubdirectories; - private DirectoriesScope(@NotNull Project project, @NotNull VirtualFile[] directories, @NotNull BitSet withSubdirectories) { + private DirectoriesScope(@NotNull Project project, + @NotNull Set directories, + @NotNull Set directoriesWithSubdirectories) { super(project); - myWithSubdirectories = withSubdirectories; myDirectories = directories; - if (directories.length < 2) { - throw new IllegalArgumentException("Expected >1 directories, but got: " + Arrays.asList(directories)); + myDirectoriesWithSubdirectories = directoriesWithSubdirectories; + if (directories.size() + directoriesWithSubdirectories.size() < 2) { + throw new IllegalArgumentException("Expected >1 directories, but got: directories " + directories + + ", directories with subdirectories " + directoriesWithSubdirectories); } } @@ -307,23 +320,10 @@ public class GlobalSearchScopesCore { } private boolean in(@NotNull VirtualFile parent) { - Set directoriesWithSubdirectories = null; - for (int i = 0; i < myDirectories.length; i++) { - VirtualFile directory = myDirectories[i]; - boolean withSubdirectories = myWithSubdirectories.get(i); - if (withSubdirectories) { - if (directory.getFileSystem().equals(parent.getFileSystem())) { - if (directoriesWithSubdirectories == null) { - directoriesWithSubdirectories = new SmartHashSet<>(); - } - directoriesWithSubdirectories.add(directory); - } - } - else if (directory.equals(parent)) { - return true; - } + if (myDirectories.contains(parent)) { + return true; } - return VfsUtilCore.isUnder(parent, directoriesWithSubdirectories); + return VfsUtilCore.isUnder(parent, myDirectoriesWithSubdirectories); } @Override @@ -344,25 +344,21 @@ public class GlobalSearchScopesCore { @Override public String toString() { //noinspection HardCodedStringLiteral - return "Directories scope: " + Arrays.asList(myDirectories); + return "Directories scope: directories " + myDirectories + ", directories with subdirectories " + myDirectoriesWithSubdirectories; } @Override public int hashCode() { - int result = 1; - for (int i = 0; i < myDirectories.length; i++) { - VirtualFile directory = myDirectories[i]; - boolean withSubdirectories = myWithSubdirectories.get(i); - result = result*31 + directory.hashCode() *31 + (withSubdirectories?1:0); - } + int result = myDirectories.hashCode(); + result = result * 31 + myDirectoriesWithSubdirectories.hashCode(); return result; } @Override public boolean equals(Object obj) { return obj instanceof DirectoriesScope && - Arrays.equals(myDirectories, ((DirectoriesScope)obj).myDirectories) && - myWithSubdirectories.equals(((DirectoriesScope)obj).myWithSubdirectories); + myDirectories.equals(((DirectoriesScope)obj).myDirectories) && + myDirectoriesWithSubdirectories.equals(((DirectoriesScope)obj).myDirectoriesWithSubdirectories); } @NotNull @@ -372,28 +368,35 @@ public class GlobalSearchScopesCore { return this; } if (scope instanceof DirectoryScope) { - if (in(((DirectoryScope)scope).myDirectory)) { + DirectoryScope other = (DirectoryScope)scope; + if (in(other.myDirectory)) { return this; } - VirtualFile[] newDirectories = ArrayUtil.append(myDirectories, ((DirectoryScope)scope).myDirectory, VirtualFile.class); - BitSet newWithSubdirectories = (BitSet)myWithSubdirectories.clone(); - newWithSubdirectories.set(myDirectories.length, ((DirectoryScope)scope).myWithSubdirectories); - return new DirectoriesScope(getProject(), newDirectories, newWithSubdirectories); + Set directories = myDirectories; + Set directoriesWithSubdirectories = myDirectoriesWithSubdirectories; + if (other.myWithSubdirectories) { + directoriesWithSubdirectories = new HashSet<>(directoriesWithSubdirectories); + directoriesWithSubdirectories.add(other.myDirectory); + } + else { + directories = new HashSet<>(directories); + directories.add(other.myDirectory); + } + return new DirectoriesScope(getProject(), directories, directoriesWithSubdirectories); } if (scope instanceof DirectoriesScope) { DirectoriesScope other = (DirectoriesScope)scope; - List newDirectories = new ArrayList<>(myDirectories.length + other.myDirectories.length); - newDirectories.addAll(Arrays.asList(myDirectories)); - BitSet newWithSubdirectories = (BitSet)myWithSubdirectories.clone(); - VirtualFile[] otherDirectories = other.myDirectories; - for (int i = 0; i < otherDirectories.length; i++) { - VirtualFile otherDirectory = otherDirectories[i]; - if (!in(otherDirectory)) { - newWithSubdirectories.set(newDirectories.size(), other.myWithSubdirectories.get(i)); - newDirectories.add(otherDirectory); - } + Set directories = myDirectories; + Set directoriesWithSubdirectories = myDirectoriesWithSubdirectories; + if (!other.myDirectories.isEmpty()) { + directories = new HashSet<>(directories); + directories.addAll(other.myDirectories); } - return new DirectoriesScope(getProject(), newDirectories.toArray(new VirtualFile[newDirectories.size()]), newWithSubdirectories); + if (!other.myDirectoriesWithSubdirectories.isEmpty()) { + directoriesWithSubdirectories = new HashSet<>(directoriesWithSubdirectories); + directoriesWithSubdirectories.addAll(other.myDirectoriesWithSubdirectories); + } + return new DirectoriesScope(getProject(), directories, directoriesWithSubdirectories); } return super.uniteWith(scope); } @@ -408,11 +411,13 @@ public class GlobalSearchScopesCore { @NotNull @Override public String getDisplayName() { - if (myDirectories.length == 1) { - VirtualFile root = myDirectories[0]; + if (myDirectories.size() + myDirectoriesWithSubdirectories.size() == 1) { + Set dirs = myDirectories.size() == 1 ? myDirectories : myDirectoriesWithSubdirectories; + VirtualFile root = Objects.requireNonNull(ContainerUtil.getFirstItem(dirs)); return "Directory '" + root.getName() + "'"; } - return "Directories " + StringUtil.join(myDirectories, file -> "'" + file.getName() + "'", ", "); + Iterable allDirs = ContainerUtil.concat(myDirectories, myDirectoriesWithSubdirectories); + return "Directories " + StringUtil.join(allDirs, file -> "'" + file.getName() + "'", ", "); } } diff --git a/platform/configuration-store-impl/src/ProjectStoreImpl.kt b/platform/configuration-store-impl/src/ProjectStoreImpl.kt index 376dbb649958..31bae5f43b60 100644 --- a/platform/configuration-store-impl/src/ProjectStoreImpl.kt +++ b/platform/configuration-store-impl/src/ProjectStoreImpl.kt @@ -29,6 +29,7 @@ import com.intellij.openapi.components.impl.stores.IComponentStore import com.intellij.openapi.components.impl.stores.IProjectStore import com.intellij.openapi.components.impl.stores.StoreUtil import com.intellij.openapi.diagnostic.runAndLogException +import com.intellij.openapi.fileTypes.FileTypeManager import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.module.impl.ModuleManagerImpl @@ -243,7 +244,7 @@ abstract class ProjectStoreBase(override final val project: ProjectImpl) : Compo } override fun isProjectFile(file: VirtualFile): Boolean { - if (!file.isInLocalFileSystem || !ProjectCoreUtil.isProjectOrWorkspaceFile(file, file.fileType)) { + if (!file.isInLocalFileSystem || !ProjectCoreUtil.isProjectOrWorkspaceFile(file)) { return false } diff --git a/platform/core-api/src/com/intellij/openapi/editor/Document.java b/platform/core-api/src/com/intellij/openapi/editor/Document.java index 58ac12ffe7c1..2a98b7a494b0 100644 --- a/platform/core-api/src/com/intellij/openapi/editor/Document.java +++ b/platform/core-api/src/com/intellij/openapi/editor/Document.java @@ -141,6 +141,13 @@ public interface Document extends UserDataHolder { @Contract(pure=true) int getLineEndOffset(int line); + /** + * @return whether the line with the given index has been modified since the document has been saved + */ + default boolean isLineModified(int line) { + return false; + } + /** * Inserts the specified text at the specified offset in the document. Line breaks in * the inserted text must be normalized as \n. diff --git a/platform/core-api/src/com/intellij/openapi/project/ProjectCoreUtil.java b/platform/core-api/src/com/intellij/openapi/project/ProjectCoreUtil.java index 6017e2ddb4a3..59a20f03c234 100644 --- a/platform/core-api/src/com/intellij/openapi/project/ProjectCoreUtil.java +++ b/platform/core-api/src/com/intellij/openapi/project/ProjectCoreUtil.java @@ -16,6 +16,7 @@ package com.intellij.openapi.project; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeRegistry; import com.intellij.openapi.fileTypes.InternalFileType; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.SystemInfoRt; @@ -26,12 +27,9 @@ import org.jetbrains.annotations.Nullable; public class ProjectCoreUtil { public static volatile Project theProject; - /** - * @deprecated Please use ProjectUtil.isProjectOrWorkspaceFile - */ - @Deprecated public static boolean isProjectOrWorkspaceFile(@NotNull VirtualFile file) { - return isProjectOrWorkspaceFile(file, file.getFileType()); + // do not use file.getFileType() to avoid autodetection by content loading for arbitrary files + return isProjectOrWorkspaceFile(file, FileTypeRegistry.getInstance().getFileTypeByFileName(file.getNameSequence())); } public static boolean isProjectOrWorkspaceFile(@NotNull VirtualFile file, @Nullable FileType fileType) { diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java index cea90c8c809b..3042ff9c82b8 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java @@ -180,6 +180,12 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { return stripTrailingSpaces(project, inChangedLinesOnly, true, new int[0]); } + @Override + public boolean isLineModified(int line) { + LineSet lineSet = myLineSet; + return lineSet != null && lineSet.isModified(line); + } + /** * @return true if stripping was completed successfully, false if the document prevented stripping by e.g. caret(s) being in the way */ diff --git a/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java b/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java index 89a470a01fad..ca742ee61114 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java @@ -518,6 +518,11 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable } } + @Override + public boolean isLineModified(int line) { + return myDelegate.isLineModified(injectedToHostLine(line)); + } + @Override @NotNull public Segment[] getHostRanges() { diff --git a/platform/platform-api/src/com/intellij/openapi/project/ProjectUtil.kt b/platform/platform-api/src/com/intellij/openapi/project/ProjectUtil.kt index 06eb32053c9b..ca86ef88e21e 100644 --- a/platform/platform-api/src/com/intellij/openapi/project/ProjectUtil.kt +++ b/platform/platform-api/src/com/intellij/openapi/project/ProjectUtil.kt @@ -74,7 +74,7 @@ fun guessProjectForFile(file: VirtualFile?): Project? = ProjectLocator.getInstan * guessProjectForFile works incorrectly - even if file is config (idea config file) first opened project will be returned */ @JvmOverloads -fun guessProjectForContentFile(file: VirtualFile, fileType: FileType = file.fileType): Project? { +fun guessProjectForContentFile(file: VirtualFile, fileType: FileType = FileTypeManager.getInstance().getFileTypeByFileName(file.nameSequence)): Project? { if (ProjectCoreUtil.isProjectOrWorkspaceFile(file, fileType)) { return null } @@ -82,10 +82,7 @@ fun guessProjectForContentFile(file: VirtualFile, fileType: FileType = file.file return ProjectManager.getInstance().openProjects.firstOrNull { !it.isDefault && it.isInitialized && !it.isDisposed && ProjectRootManager.getInstance(it).fileIndex.isInContent(file) } } -fun isProjectOrWorkspaceFile(file: VirtualFile): Boolean { - // do not use file.getFileType() to avoid autodetection by content loading for arbitrary files - return ProjectCoreUtil.isProjectOrWorkspaceFile(file, FileTypeManager.getInstance().getFileTypeByFileName(file.name)) -} +fun isProjectOrWorkspaceFile(file: VirtualFile): Boolean = ProjectCoreUtil.isProjectOrWorkspaceFile(file) fun guessCurrentProject(component: JComponent?): Project { var project: Project? = null diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java b/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java index 7c6de1ea7ba6..770ee03c67da 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java @@ -367,12 +367,13 @@ public class GlassPaneDialogWrapperPeer extends DialogWrapperPeer implements Foc private void hidePopupsIfNeeded() { if (!SystemInfo.isMac) return; - StackingPopupDispatcher.getInstance().hidePersistentPopups(); + final StackingPopupDispatcher stackingPopupDispatcher = StackingPopupDispatcher.getInstance(); + stackingPopupDispatcher.hidePersistentPopups(); Disposer.register(myDialog, new Disposable() { @Override public void dispose() { - StackingPopupDispatcher.getInstance().restorePersistentPopups(); + stackingPopupDispatcher.restorePersistentPopups(); } }); } diff --git a/platform/platform-tests/testSrc/com/intellij/util/StringBuilderSpinAllocatorTest.java b/platform/platform-tests/testSrc/com/intellij/util/StringBuilderSpinAllocatorTester.java similarity index 87% rename from platform/platform-tests/testSrc/com/intellij/util/StringBuilderSpinAllocatorTest.java rename to platform/platform-tests/testSrc/com/intellij/util/StringBuilderSpinAllocatorTester.java index e137dfe34355..68023dd80352 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/StringBuilderSpinAllocatorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/StringBuilderSpinAllocatorTester.java @@ -16,19 +16,24 @@ package com.intellij.util; import com.intellij.concurrency.JobLauncher; -import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.PlatformTestUtil; +import org.junit.Assert; import java.util.Collections; import java.util.Random; import static org.junit.Assume.assumeTrue; -public class StringBuilderSpinAllocatorTest extends PlatformTestCase { +public class StringBuilderSpinAllocatorTester { + + public static void main(String[] args) { + testSequentialPerformance(); + testConcurrentPerformance(); + } public static final int THREADS = 1000; - public void testSequentialPerformance() { + private static void testSequentialPerformance() { assumeTrue(!PlatformTestUtil.COVERAGE_ENABLED_BUILD); for (int i=0; i<10; i++) { long spinTime = time(count, spinAlloc); @@ -36,7 +41,7 @@ public class StringBuilderSpinAllocatorTest extends PlatformTestCase { System.out.println("regular: " + regularTime + "; spin :" +spinTime+"; ratio: "+(10*spinTime/regularTime)/10.0+" times"); } } - public void testConcurrentPerformance() { + private static void testConcurrentPerformance() { assumeTrue(!PlatformTestUtil.COVERAGE_ENABLED_BUILD); for (int i=0; i<10; i++) { long spinTime = concurrentTime(count/THREADS, spinAlloc); @@ -53,13 +58,14 @@ public class StringBuilderSpinAllocatorTest extends PlatformTestCase { return true; }); - assertTrue(ok); + Assert.assertTrue(ok); }); } static final int count = 100000; static final int iter = 1000; static Runnable spinAlloc = new Runnable() { + @SuppressWarnings("deprecation") @Override public void run() { for (int i = 0; i < iter; ++i) { @@ -77,6 +83,7 @@ public class StringBuilderSpinAllocatorTest extends PlatformTestCase { } }; static Runnable regularAlloc = new Runnable() { + @SuppressWarnings("MismatchedQueryAndUpdateOfStringBuilder") @Override public void run() { for (int i = 0; i < iter; ++i) { diff --git a/platform/util/src/com/intellij/util/StringBuilderSpinAllocator.java b/platform/util/src/com/intellij/util/StringBuilderSpinAllocator.java index ecd8e758808b..e77474d99b49 100644 --- a/platform/util/src/com/intellij/util/StringBuilderSpinAllocator.java +++ b/platform/util/src/com/intellij/util/StringBuilderSpinAllocator.java @@ -18,6 +18,7 @@ package com.intellij.util; /** * StringBuilderSpinAllocator reuses StringBuilder instances performing non-blocking allocation and dispose. + * @deprecated Simple allocation is faster than this (according to StringBuilderSpinAllocatorTester) */ public class StringBuilderSpinAllocator { diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index c2f1a47891f4..8901c09561f3 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -2008,6 +2008,45 @@ public class UIUtil { drawImage(g, image, x, y, -1, -1, observer); } + public static void drawImage(Graphics g, Image image, @Nullable Rectangle dstRect, @Nullable Rectangle srcRect, ImageObserver observer) { + Image drawImage = image; + if (image instanceof JBHiDPIScaledImage) { + drawImage = ((JBHiDPIScaledImage)image).getDelegate(); + if (drawImage == null) { + drawImage = image; + } + } + int dx = 0; + int dy = 0; + int dw = -1; + int dh = -1; + if (dstRect != null) { + dx = dstRect.x; + dy = dstRect.y; + dw = dstRect.width; + dh = dstRect.height; + } + if (dw == -1 && dh == -1) { + dw = ImageUtil.getUserWidth(image); + dh = ImageUtil.getUserHeight(image); + } + int sx = 0; + int sy = 0; + int sw = -1; + int sh = -1; + if (srcRect != null) { + sx = srcRect.x; + sy = srcRect.y; + sw = srcRect.width; + sh = srcRect.height; + } + if (sw == -1 && sh == -1) { + sw = ImageUtil.getRealWidth(image); + sh = ImageUtil.getRealHeight(image); + } + g.drawImage(drawImage, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, observer); + } + public static void drawImage(Graphics g, Image image, int x, int y, int width, int height, ImageObserver observer) { if (image instanceof JBHiDPIScaledImage) { Image img = ((JBHiDPIScaledImage)image).getDelegate(); @@ -2028,7 +2067,7 @@ public class UIUtil { g.drawImage(image, x, y, observer); } else { - g.drawImage(image, x, y, x + width, y + height, observer); + g.drawImage(image, x, y, x + width, y + height, 0, 0, width, height, observer); } }