diff --git a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionExFilterFactory.java b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionExFilterFactory.java index 433da78acb21..9b42c38d990c 100644 --- a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionExFilterFactory.java +++ b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionExFilterFactory.java @@ -39,16 +39,17 @@ import java.util.Map; * @author gregsh */ public class ExceptionExFilterFactory implements ExceptionFilterFactory { + @NotNull @Override - public Filter create(GlobalSearchScope searchScope) { + public Filter create(@NotNull GlobalSearchScope searchScope) { return new MyFilter(searchScope); } private static class MyFilter implements Filter, FilterMixin { - private final GlobalSearchScope myScope; + private final ExceptionInfoCache myCache; public MyFilter(@NotNull final GlobalSearchScope scope) { - myScope = scope; + myCache = new ExceptionInfoCache(scope); } public Result applyFilter(final String line, final int textEndOffset) { @@ -68,7 +69,7 @@ public class ExceptionExFilterFactory implements ExceptionFilterFactory { Map> visited = new THashMap>(); final Trinity emptyInfo = Trinity.create(null, null, null); - final ExceptionWorker worker = new ExceptionWorker(myScope.getProject(), myScope); + final ExceptionWorker worker = new ExceptionWorker(myCache); for (int i = 0; i < copiedFragment.getLineCount(); i++) { final int lineStartOffset = copiedFragment.getLineStartOffset(i); final int lineEndOffset = copiedFragment.getLineEndOffset(i); diff --git a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java index 38a8a0180084..24b2bb252e4b 100644 --- a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java +++ b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java @@ -20,14 +20,14 @@ import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; public class ExceptionFilter implements Filter, DumbAware { - private final GlobalSearchScope myScope; + private final ExceptionInfoCache myCache; public ExceptionFilter(@NotNull final GlobalSearchScope scope) { - myScope = scope; + myCache = new ExceptionInfoCache(scope); } public Result applyFilter(final String line, final int textEndOffset) { - ExceptionWorker worker = new ExceptionWorker(myScope.getProject(), myScope); + ExceptionWorker worker = new ExceptionWorker(myCache); worker.execute(line, textEndOffset); return worker.getResult(); } diff --git a/java/java-impl/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationExceptionFilter.java b/java/java-impl/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationExceptionFilter.java index b52273b0ecbe..a26ca3609e07 100644 --- a/java/java-impl/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationExceptionFilter.java +++ b/java/java-impl/src/com/intellij/openapi/vcs/contentAnnotation/VcsContentAnnotationExceptionFilter.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs.contentAnnotation; +import com.intellij.execution.filters.ExceptionInfoCache; import com.intellij.execution.filters.ExceptionWorker; import com.intellij.execution.filters.Filter; import com.intellij.execution.filters.FilterMixin; @@ -54,15 +55,15 @@ import java.util.*; public class VcsContentAnnotationExceptionFilter implements Filter, FilterMixin { private final Project myProject; private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.contentAnnotation.VcsContentAnnotationExceptionFilter"); - private final GlobalSearchScope myScope; private final VcsContentAnnotationSettings mySettings; - private Map myRevNumbersCache; + private final Map myRevNumbersCache; + private final ExceptionInfoCache myCache; public VcsContentAnnotationExceptionFilter(@NotNull GlobalSearchScope scope) { - myScope = scope; myProject = scope.getProject(); mySettings = VcsContentAnnotationSettings.getInstance(myProject); myRevNumbersCache = new HashMap(); + myCache = new ExceptionInfoCache(scope); } private static class MyAdditionalHighlight extends AdditionalHighlight { @@ -75,10 +76,10 @@ public class VcsContentAnnotationExceptionFilter implements Filter, FilterMixin EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme(); final TextAttributes changedColor = globalScheme.getAttributes(DiffColors.DIFF_MODIFIED); if (source == null) { - TextAttributes atts = + TextAttributes attrs = globalScheme.getAttributes(CodeInsightColors.CLASS_NAME_ATTRIBUTES).clone(); - atts.setBackgroundColor(changedColor.getBackgroundColor()); - return atts; + attrs.setBackgroundColor(changedColor.getBackgroundColor()); + return attrs; } TextAttributes clone = source.clone(); clone.setBackgroundColor(changedColor.getBackgroundColor()); @@ -103,7 +104,7 @@ public class VcsContentAnnotationExceptionFilter implements Filter, FilterMixin for (int i = 0; i < copiedFragment.getLineCount(); i++) { final int lineStartOffset = copiedFragment.getLineStartOffset(i); final int lineEndOffset = copiedFragment.getLineEndOffset(i); - final ExceptionWorker worker = new ExceptionWorker(myProject, myScope); + final ExceptionWorker worker = new ExceptionWorker(myCache); final String[] lineText = new String[1]; ApplicationManager.getApplication().runReadAction(new Runnable() { @Override @@ -216,7 +217,7 @@ public class VcsContentAnnotationExceptionFilter implements Filter, FilterMixin } } - private Document getDocumentForFile(final ExceptionWorker worker) { + private static Document getDocumentForFile(final ExceptionWorker worker) { return ApplicationManager.getApplication().runReadAction(new Computable() { @Override public Document compute() { @@ -231,7 +232,9 @@ public class VcsContentAnnotationExceptionFilter implements Filter, FilterMixin } // line numbers - private List findMethodRange(final ExceptionWorker worker, final Document document, final Trinity previousLineResult) { + private static List findMethodRange(final ExceptionWorker worker, + final Document document, + final Trinity previousLineResult) { return ApplicationManager.getApplication().runReadAction(new Computable>() { @Override public List compute() { @@ -249,7 +252,7 @@ public class VcsContentAnnotationExceptionFilter implements Filter, FilterMixin // null - check all @Nullable - private List selectMethod(final PsiMethod[] methods, final Trinity previousLineResult) { + private static List selectMethod(final PsiMethod[] methods, final Trinity previousLineResult) { if (previousLineResult == null || previousLineResult.getThird() == null) return null; final List result = new SmartList(); @@ -270,7 +273,7 @@ public class VcsContentAnnotationExceptionFilter implements Filter, FilterMixin return result; } - private List getTextRangeForMethod(final ExceptionWorker worker, Trinity previousLineResult) { + private static List getTextRangeForMethod(final ExceptionWorker worker, Trinity previousLineResult) { String method = worker.getMethod(); PsiClass psiClass = worker.getPsiClass(); PsiMethod[] methods; diff --git a/java/openapi/src/com/intellij/execution/filters/ExceptionInfoCache.java b/java/openapi/src/com/intellij/execution/filters/ExceptionInfoCache.java new file mode 100644 index 000000000000..e0ffc7fc9b40 --- /dev/null +++ b/java/openapi/src/com/intellij/execution/filters/ExceptionInfoCache.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.filters; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiFile; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.reference.SoftReference; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.ConcurrentMap; + +/** + * @author peter + */ +public class ExceptionInfoCache { + private final ConcurrentMap>> myCache = ContainerUtil.newConcurrentMap(); + private final Project myProject; + private final GlobalSearchScope mySearchScope; + + public ExceptionInfoCache(GlobalSearchScope searchScope) { + myProject = ObjectUtils.assertNotNull(searchScope.getProject()); + mySearchScope = searchScope; + } + + @NotNull public Project getProject() { + return myProject; + } + + @NotNull + private PsiClass[] findClassesPreferringMyScope(String className) { + JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); + PsiClass[] result = psiFacade.findClasses(className, mySearchScope); + return result.length != 0 ? result : psiFacade.findClasses(className, GlobalSearchScope.allScope(myProject)); + } + + Pair resolveClass(String className) { + Pair cached = SoftReference.dereference(myCache.get(className)); + if (cached != null) { + return cached; + } + + PsiClass[] classes = findClassesPreferringMyScope(className); + if (classes.length == 0) { + final int dollarIndex = className.indexOf('$'); + if (dollarIndex >= 0) { + classes = findClassesPreferringMyScope(className.substring(0, dollarIndex)); + } + } + + PsiFile[] files = new PsiFile[classes.length]; + for (int i = 0; i < classes.length; i++) { + files[i] = (PsiFile)classes[i].getContainingFile().getNavigationElement(); + } + + Pair result = Pair.create(classes, files); + myCache.put(className, new SoftReference>(result)); + return result; + } + +} diff --git a/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java index ff02aadc3856..c89be37e03b0 100644 --- a/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java +++ b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java @@ -21,13 +21,12 @@ import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.Trinity; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiFile; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.util.ArrayUtil; import com.intellij.util.ui.UIUtil; @@ -62,16 +61,16 @@ public class ExceptionWorker { } private final Project myProject; - private final GlobalSearchScope mySearchScope; private Filter.Result myResult; private PsiClass[] myClasses = PsiClass.EMPTY_ARRAY; private PsiFile[] myFiles = PsiFile.EMPTY_ARRAY; private String myMethod; private Trinity myInfo; + private final ExceptionInfoCache myCache; - public ExceptionWorker(@NotNull Project project, @NotNull GlobalSearchScope searchScope) { - myProject = project; - mySearchScope = searchScope; + public ExceptionWorker(@NotNull ExceptionInfoCache cache) { + myProject = cache.getProject(); + myCache = cache; } public void execute(final String line, final int textEndOffset) { @@ -93,11 +92,9 @@ public class ExceptionWorker { final String lineString = fileAndLine.substring(colonIndex + 1); try { final int lineNumber = Integer.parseInt(lineString); - myClasses = findPositionClasses(line); - myFiles = new PsiFile[myClasses.length]; - for (int i = 0; i < myClasses.length; i++) { - myFiles[i] = (PsiFile)myClasses[i].getContainingFile().getNavigationElement(); - } + Pair pair = myCache.resolveClass(myInfo.first.substring(line).trim()); + myClasses = pair.first; + myFiles = pair.second; if (myFiles.length == 0) { // try find the file with the required name //todo[nik] it would be better to use FilenameIndex here to honor the scope by it isn't accessible in Open API @@ -149,25 +146,6 @@ public class ExceptionWorker { } } - private PsiClass[] findPositionClasses(String line) { - String className = myInfo.first.substring(line).trim(); - PsiClass[] result = findClassesPreferringMyScope(className); - if (result.length == 0) { - final int dollarIndex = className.indexOf('$'); - if (dollarIndex >= 0) { - result = findClassesPreferringMyScope(className.substring(0, dollarIndex)); - } - } - return result; - } - - @NotNull - private PsiClass[] findClassesPreferringMyScope(String className) { - JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); - PsiClass[] result = psiFacade.findClasses(className, mySearchScope); - return result.length != 0 ? result : psiFacade.findClasses(className, GlobalSearchScope.allScope(myProject)); - } - public Filter.Result getResult() { return myResult; } @@ -206,18 +184,18 @@ public class ExceptionWorker { } } - final int lparenIdx = line.indexOf('(', startIdx); - if (lparenIdx < 0) return null; - final int dotIdx = line.lastIndexOf('.', lparenIdx); + final int lParenIdx = line.indexOf('(', startIdx); + if (lParenIdx < 0) return null; + final int dotIdx = line.lastIndexOf('.', lParenIdx); if (dotIdx < 0 || dotIdx < startIdx) return null; - final int rparenIdx = line.indexOf(')', lparenIdx); - if (rparenIdx < 0) return null; + final int rParenIdx = line.indexOf(')', lParenIdx); + if (rParenIdx < 0) return null; // class, method, link return Trinity.create(new TextRange(startIdx + 1 + (startIdx >= 0 ? AT.length() : 0), handleSpaces(line, dotIdx, -1, true)), - new TextRange(handleSpaces(line, dotIdx + 1, 1, true), handleSpaces(line, lparenIdx + 1, -1, true)), - new TextRange(lparenIdx, rparenIdx)); + new TextRange(handleSpaces(line, dotIdx + 1, 1, true), handleSpaces(line, lParenIdx + 1, -1, true)), + new TextRange(lParenIdx, rParenIdx)); } private static int handleSpaces(String line, int pos, int delta, boolean skip) {