diff --git a/java/compiler/javac2/src/com/intellij/ant/ClassFilterAnnotationRegexp.java b/java/compiler/javac2/src/com/intellij/ant/ClassFilterAnnotationRegexp.java new file mode 100644 index 000000000000..bb69d806b570 --- /dev/null +++ b/java/compiler/javac2/src/com/intellij/ant/ClassFilterAnnotationRegexp.java @@ -0,0 +1,30 @@ +/* + * 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.ant; + +import org.apache.tools.ant.types.RegularExpression; + +/** + * A pattern which is used to skip NotNull assertion instrumentation on classes that have at least one annotation matching this pattern. + * + * Example usage: + * + * + * + * + */ +public class ClassFilterAnnotationRegexp extends RegularExpression { +} diff --git a/java/compiler/javac2/src/com/intellij/ant/Javac2.java b/java/compiler/javac2/src/com/intellij/ant/Javac2.java index e5b8aee7130a..d41e5dc70ebd 100644 --- a/java/compiler/javac2/src/com/intellij/ant/Javac2.java +++ b/java/compiler/javac2/src/com/intellij/ant/Javac2.java @@ -25,10 +25,8 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Javac; import org.apache.tools.ant.types.Path; -import org.jetbrains.org.objectweb.asm.ClassReader; -import org.jetbrains.org.objectweb.asm.ClassVisitor; -import org.jetbrains.org.objectweb.asm.ClassWriter; -import org.jetbrains.org.objectweb.asm.Opcodes; +import org.apache.tools.ant.util.regexp.Regexp; +import org.jetbrains.org.objectweb.asm.*; import java.io.*; import java.net.MalformedURLException; @@ -40,6 +38,7 @@ public class Javac2 extends Javac { private ArrayList myFormFiles; private List myNestedFormPathList; private boolean instrumentNotNull = true; + private List myClassFilterAnnotationRegexpList = new ArrayList(0); public Javac2() { } @@ -75,6 +74,16 @@ public class Javac2 extends Javac { this.instrumentNotNull = instrumentNotNull; } + /** + * Allows to specify patterns of annotation class names to skip NotNull instrumentation on classes which have at least one + * annotation matching at least one of the given patterns + * + * @param regexp the regular expression for JVM internal name (slash-separated) of annotations + */ + public void add(final ClassFilterAnnotationRegexp regexp) { + myClassFilterAnnotationRegexpList.add(regexp.getRegexp(getProject())); + } + /** * The overridden setter method that warns about unsupported option. * @@ -425,8 +434,8 @@ public class Javac2 extends Javac { ClassReader reader = new ClassReader(inputStream); int version = getClassFileVersion(reader); - - if (version >= Opcodes.V1_5) { + + if (version >= Opcodes.V1_5 && !shouldBeSkippedByAnnotationPattern(reader)) { ClassWriter writer = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder); if (NotNullVerifyingInstrumenter.processClassFile(reader, writer)) { @@ -471,6 +480,30 @@ public class Javac2 extends Javac { return classfileVersion[0]; } + private boolean shouldBeSkippedByAnnotationPattern(ClassReader reader) { + if (myClassFilterAnnotationRegexpList.isEmpty()) { + return false; + } + + final boolean[] result = new boolean[]{false}; + reader.accept(new ClassVisitor(Opcodes.ASM5) { + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if (!result[0]) { + String internalName = Type.getType(desc).getInternalName(); + for (Regexp regexp : myClassFilterAnnotationRegexpList) { + if (regexp.matches(internalName)) { + result[0] = true; + break; + } + } + } + return null; + } + }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + + return result[0]; + } + private void fireError(final String message) { if (failOnError) { throw new BuildException(message, getLocation()); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/actions/ReformatCodeActionInEditorTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/actions/ReformatCodeActionInEditorTest.java index 286de18ffd6d..0dd2bcebc27d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/actions/ReformatCodeActionInEditorTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/actions/ReformatCodeActionInEditorTest.java @@ -43,13 +43,13 @@ public class ReformatCodeActionInEditorTest extends LightCodeInsightFixtureTestC String before = null; if (options.isProcessOnlyChangedText()) { - myFixture.configureByFile(getTestDataPath() + getTestName(true) + "_revision.java"); + myFixture.configureByFile(getTestName(true) + "_revision.java"); PsiFile file = myFixture.getFile(); Document document = myFixture.getDocument(file); before = document.getText(); } - myFixture.configureByFile(getTestDataPath() + getTestName(true) + "_before.java"); + myFixture.configureByFile(getTestName(true) + "_before.java"); if (before != null) { myFixture.getFile().putUserData(FormatChangedTextUtil.TEST_REVISION_CONTENT, before); diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaPredefinedConfigurations.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaPredefinedConfigurations.java index a1d505a40259..8c1c9a3b4986 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaPredefinedConfigurations.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaPredefinedConfigurations.java @@ -176,6 +176,7 @@ class JavaPredefinedConfigurations { createSearchTemplateInfo(SSRBundle.message("predefined.configuration.javadoc.tags"),"/** @'Tag+ '_TagValue* */", METADATA_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.xdoclet.metadata"),"/** @'Tag \n '_Property+\n*/", METADATA_TYPE), + createSearchTemplateInfo(SSRBundle.message("predefined.configuration.annotations"), "@'_Annotation", METADATA_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.annotated.class"), "@'_Annotation( )\n" + "class 'Class {}", METADATA_TYPE), diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java index 1adf8d760054..e7f5267da2f0 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java @@ -755,11 +755,7 @@ public class JavaMatchingVisitor extends JavaElementVisitor { } if (list != null && list.getTypeParameterElements().length > 0) { - boolean result = typeparams != null && - myMatchingVisitor.matchInAnyOrder( - list.getTypeParameterElements(), - typeparams - ); + boolean result = typeparams != null && myMatchingVisitor.matchSequentially(list.getTypeParameterElements(), typeparams); if (!result) return false; el = ((PsiJavaCodeReferenceElement)el).getReferenceNameElement(); @@ -851,8 +847,9 @@ public class JavaMatchingVisitor extends JavaElementVisitor { else { PsiElement element2 = ((PsiJavaReference)el2).resolve(); - if (element2 != null) { - return text.equals(((PsiClass)element2).getQualifiedName()); + if (element2 instanceof PsiClass) { + final PsiClass aClass = (PsiClass)element2; + return text.equals(aClass.getQualifiedName()) || text.equals(aClass.getName()); } else { return MatchUtils.compareWithNoDifferenceToPackage(text, text2); diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java index e416c0cbe778..a30cff344ae6 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/compiler/JavaCompilingVisitor.java @@ -8,6 +8,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.structuralsearch.*; import com.intellij.structuralsearch.impl.matcher.CompiledPattern; import com.intellij.structuralsearch.impl.matcher.JavaCompiledPattern; @@ -211,7 +212,7 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { } currentReference = (PsiReferenceExpression)qualifier; } - if (!hasNoNestedSubstitutionHandlers) { + if (!hasNoNestedSubstitutionHandlers && PsiTreeUtil.getChildOfType(reference, PsiAnnotation.class) == null) { createAndSetSubstitutionHandlerFromReference( reference, resolve != null ? ((PsiClass)resolve).getQualifiedName() : reference.getText(), @@ -284,14 +285,26 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { return; } } + else if (firstChild instanceof PsiModifierList) { + final PsiModifierList modifierList = (PsiModifierList)firstChild; + final PsiAnnotation[] annotations = modifierList.getAnnotations(); + if (annotations.length != 1) { + throw new UnsupportedPatternException("Pattern is malformed"); + } + for (String modifier : PsiModifier.MODIFIERS) { + if (modifierList.hasExplicitModifier(modifier)) { + throw new UnsupportedPatternException("Pattern is malformed"); + } + } + myCompilingVisitor.setHandler(psiDeclarationStatement, new AnnotationHandler()); + final MatchingHandler handler = myCompilingVisitor.getContext().getPattern().getHandler(psiDeclarationStatement); + handler.setFilter(AnnotationFilter.getInstance()); + return; + } final MatchingHandler handler = new DeclarationStatementHandler(); myCompilingVisitor.getContext().getPattern().setHandler(psiDeclarationStatement, handler); - PsiElement previousNonWhiteSpace = psiDeclarationStatement.getPrevSibling(); - - while (previousNonWhiteSpace instanceof PsiWhiteSpace) { - previousNonWhiteSpace = previousNonWhiteSpace.getPrevSibling(); - } + final PsiElement previousNonWhiteSpace = PsiTreeUtil.skipSiblingsBackward(psiDeclarationStatement, PsiWhiteSpace.class); if (previousNonWhiteSpace instanceof PsiComment) { ((DeclarationStatementHandler)handler) @@ -459,6 +472,7 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor { } private static void handleReferenceText(String refname, CompileContext compileContext) { + System.out.println("JavaCompilingVisitor" + ".handleReferenceText(" + refname + ", " + compileContext + ")"); if (refname == null) return; if (compileContext.getPattern().isTypedVar(refname)) { diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/AnnotationFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/AnnotationFilter.java new file mode 100644 index 000000000000..82cb4baadb20 --- /dev/null +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/AnnotationFilter.java @@ -0,0 +1,40 @@ +/* + * 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.structuralsearch.impl.matcher.filters; + +import com.intellij.dupLocator.util.NodeFilter; +import com.intellij.psi.PsiAnnotation; +import com.intellij.psi.PsiElement; + +/** + * @author Bas + */ +public class AnnotationFilter implements NodeFilter { + + private static class NodeFilterHolder { + private static final NodeFilter instance = new AnnotationFilter(); + } + + public static NodeFilter getInstance() { + return NodeFilterHolder.instance; + } + + private AnnotationFilter() {} + + public boolean accepts(PsiElement element) { + return element instanceof PsiAnnotation; + } +} diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/JavaDocFilter.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/JavaDocFilter.java index d12e9cbd0440..0499f5469d57 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/JavaDocFilter.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/filters/JavaDocFilter.java @@ -13,11 +13,9 @@ import com.intellij.psi.javadoc.PsiDocComment; * To change this template use Options | File Templates. */ public class JavaDocFilter implements NodeFilter { - protected boolean result; public boolean accepts(PsiElement element) { - return element instanceof PsiDocCommentOwner || - element instanceof PsiDocComment; + return element instanceof PsiDocCommentOwner || element instanceof PsiDocComment; } private static class NodeFilterHolder { diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/AnnotationHandler.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/AnnotationHandler.java new file mode 100644 index 000000000000..b94db3dea319 --- /dev/null +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/AnnotationHandler.java @@ -0,0 +1,39 @@ +/* + * 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.structuralsearch.impl.matcher.handlers; + +import com.intellij.psi.PsiElement; +import com.intellij.structuralsearch.impl.matcher.MatchContext; +import com.intellij.structuralsearch.impl.matcher.filters.AnnotationFilter; + +/** + * @author Bas + */ +public class AnnotationHandler extends MatchingHandler { + + public AnnotationHandler() { + setFilter(AnnotationFilter.getInstance()); + } + + public boolean match(PsiElement patternNode, PsiElement matchedNode, MatchContext context) { + if (!super.match(patternNode,matchedNode,context)) { + return false; + } + + final PsiElement element = patternNode.getFirstChild().getFirstChild(); + return context.getMatcher().match(element, matchedNode); + } +} diff --git a/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java b/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java index dfc355879cf0..a052f8906060 100644 --- a/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java +++ b/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java @@ -35,9 +35,25 @@ public interface DocumentationProvider { */ ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.documentationProvider"); + /** + * Returns the text to show in the Ctrl-hover popup for the specified element. + * + * @param element the element for which the documentation is requested (for example, if the mouse is over + * a method reference, this will be the method to which the reference is resolved). + * @param originalElement the element under the mouse cursor + * @return the documentation to show, or null if the provider can't provide any documentation for this element. + */ @Nullable String getQuickNavigateInfo(PsiElement element, PsiElement originalElement); + /** + * Returns the list of possible URLs to show as external documentation for the specified element. + * @param element the element for which the documentation is requested (for example, if the mouse is over + * a method reference, this will be the method to which the reference is resolved). + * @param originalElement the element under the mouse cursor + * @return the list of URLs to open in the browser. If the list contains a single URL, it will be opened. + * If the list contains multiple URls, the user will be prompted to choose one of them. + */ @Nullable List getUrlFor(PsiElement element, PsiElement originalElement); @@ -45,10 +61,11 @@ public interface DocumentationProvider { * Callback for asking the doc provider for the complete documentation. *

* Underlying implementation may be time-consuming, that's why this method is expected not to be called from EDT. - * - * @param element target element which documentation is being requested - * @param originalElement element initially picked up from the current context - * @return target element's documentation (if any) + * + * @param element the element for which the documentation is requested (for example, if the mouse is over + * a method reference, this will be the method to which the reference is resolved). + * @param originalElement the element under the mouse cursor + * @return target element's documentation (if any) */ @Nullable String generateDoc(PsiElement element, @Nullable PsiElement originalElement); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SubstitutionHandler.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SubstitutionHandler.java index 0c84e3bb2436..2fb20927d329 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SubstitutionHandler.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/handlers/SubstitutionHandler.java @@ -521,10 +521,6 @@ public class SubstitutionHandler extends MatchingHandler { this.target = target; } - public MatchingHandler getMatchHandler() { - return matchHandler; - } - public void setMatchHandler(MatchingHandler matchHandler) { this.matchHandler = matchHandler; } diff --git a/platform/structuralsearch/source/messages/SSRBundle.properties b/platform/structuralsearch/source/messages/SSRBundle.properties index 9cf09ff14739..d65271e16c46 100644 --- a/platform/structuralsearch/source/messages/SSRBundle.properties +++ b/platform/structuralsearch/source/messages/SSRBundle.properties @@ -117,7 +117,8 @@ predefined.configuration.usage.of.derived.type.in.cast=usage of derived type in predefined.configuration.annotated.methods=annotated methods predefined.configuration.not.annotated.methods=not annotated methods predefined.configuration.annotation.declarations=annotation declarations -predefined.configuration.annotated.class=annotated class +predefined.configuration.annotations=annotations +predefined.configuration.annotated.class=annotated classes predefined.configuration.entity.ejb=entity ejb predefined.configuration.generic.methods=generic methods predefined.configuration.cloneable.implementations=Cloneable implementations diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 2908e9a6f20b..3de78a14a9f7 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -1320,8 +1320,8 @@ public class StructuralSearchTest extends StructuralSearchTestCase { String s82_8 = "'T<'_Subst+>"; assertEquals( "typed symbol", - findMatchesCount(s81_4,s82_8), - 6 + 8, + findMatchesCount(s81_4,s82_8) ); String s81_5 = "class A { HashMap variable = new HashMap(\"aaa\");}"; @@ -1336,6 +1336,16 @@ public class StructuralSearchTest extends StructuralSearchTestCase { findMatchesCount(s81_5, "new 'Type<>('_Param)"), 0 ); + assertEquals( + "order of parameters matters", + 0, + findMatchesCount(s81_5, "HashMap") + ); + assertEquals( + "order of parameters matters 2", + 2, + findMatchesCount(s81_5, "HashMap") + ); String source1 = "class Comparator { private Comparator c; private Comparator d; }"; String target1 = "java.util.Comparator 'a;"; @@ -2408,6 +2418,24 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("Find anno parameter value",0,findMatchesCount(s11,s12_5)); assertEquals("Find anno parameter value",4,findMatchesCount(s11,s12_6)); assertEquals("Find anno parameter value",4,findMatchesCount(s11,s12_7)); + + String source1 = "class A {" + + " void m() {" + + " new @B Object();" + + " }" + + "}"; + assertEquals("Find annotated new expression", 1, findMatchesCount(source1, "new Object()")); + assertEquals("Find annotated new expression", 1, findMatchesCount(source1, "new @B Object()")); + assertEquals("Find annotated new expression", 0, findMatchesCount(source1, "new @C Object()")); + + String source2 = "@X\n" + + "class A {\n" + + " @Y int value;" + + " @Y int void m(@Z int i) {\n" + + " return 1;\n" + + " }\n" + + "}\n"; + assertEquals("Find all annotations", 4, findMatchesCount(source2, "@'_Annotation")); } public void testBoxingAndUnboxing() { @@ -2938,6 +2966,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " Runnable r = System.out::println;" + " Runnable s = this::hashCode;" + " Runnable t = this::new;" + + " Runnable u = @AA A::new;" + " static {" + " System.out.println();" + " }" + @@ -2950,7 +2979,10 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("should find method reference 2", 2, findMatchesCount(source, pattern2)); String pattern3 = "'_a::'_b"; - assertEquals("should find all method references", 3, findMatchesCount(source, pattern3)); + assertEquals("should find all method references", 4, findMatchesCount(source, pattern3)); + + String pattern4 = "@AA A::new"; + assertEquals("should find annotated method references", 1, findMatchesCount(source, pattern4)); } public void testNoUnexpectedException() { diff --git a/plugins/git4idea/src/git4idea/log/GitLogProvider.java b/plugins/git4idea/src/git4idea/log/GitLogProvider.java index 3c4e0a3034c7..f152a7a951a2 100644 --- a/plugins/git4idea/src/git4idea/log/GitLogProvider.java +++ b/plugins/git4idea/src/git4idea/log/GitLogProvider.java @@ -32,6 +32,7 @@ import com.intellij.vcs.log.graph.GraphCommit; import com.intellij.vcs.log.graph.impl.facade.PermanentGraphImpl; import com.intellij.vcs.log.impl.HashImpl; import com.intellij.vcs.log.impl.LogDataImpl; +import com.intellij.vcs.log.util.StopWatch; import git4idea.*; import git4idea.branch.GitBranchUtil; import git4idea.config.GitVersionSpecialty; @@ -135,8 +136,10 @@ public class GitLogProvider implements VcsLogProvider { } } + StopWatch sw = StopWatch.start("sorting commits in " + root.getName()); List sortedCommits = VcsLogSorter.sortByDateTopoOrder(allDetails); sortedCommits = sortedCommits.subList(0, Math.min(sortedCommits.size(), requirements.getCommitCount())); + sw.report(); if (LOG.isDebugEnabled()) { validateDataAndReportError(root, allRefs, sortedCommits, data, branches, currentTagNames, commitsFromTags); @@ -152,6 +155,7 @@ public class GitLogProvider implements VcsLogProvider { final Set manuallyReadBranches, @Nullable final Set currentTagNames, @Nullable final DetailedLogData commitsFromTags) { + StopWatch sw = StopWatch.start("validating data in " + root.getName()); final Set refs = ContainerUtil.map2Set(allRefs, new Function() { @Override public Hash fun(VcsRef ref) { @@ -181,6 +185,7 @@ public class GitLogProvider implements VcsLogProvider { return 0; } }, refs); + sw.report(); } @SuppressWarnings("StringConcatenationInsideStringBufferAppend") @@ -264,8 +269,10 @@ public class GitLogProvider implements VcsLogProvider { @NotNull private Set readCurrentTagNames(@NotNull VirtualFile root) throws VcsException { + StopWatch sw = StopWatch.start("reading tags in " + root.getName()); Set tags = newHashSet(); GitTag.listAsStrings(myProject, root, tags, null); + sw.report(); return tags; } @@ -289,9 +296,11 @@ public class GitLogProvider implements VcsLogProvider { @NotNull private DetailedLogData loadSomeCommitsOnTaggedBranches(@NotNull VirtualFile root, int commitCount, @NotNull Collection unmatchedTags) throws VcsException { + StopWatch sw = StopWatch.start("loading commits on tagged branch in " + root.getName()); List params = new ArrayList(); params.add("--max-count=" + commitCount); params.addAll(unmatchedTags); + sw.report(); return GitHistoryUtils.loadMetadata(myProject, root, true, ArrayUtil.toStringArray(params)); } @@ -337,6 +346,7 @@ public class GitLogProvider implements VcsLogProvider { @NotNull private Set readBranches(@NotNull GitRepository repository) { + StopWatch sw = StopWatch.start("readBranches in " + repository.getRoot().getName()); VirtualFile root = repository.getRoot(); repository.update(); Collection localBranches = repository.getBranches().getLocalBranches(); @@ -354,6 +364,7 @@ public class GitLogProvider implements VcsLogProvider { if (currentRevision != null) { // null => fresh repository refs.add(myVcsObjectsFactory.createRef(HashImpl.build(currentRevision), "HEAD", GitRefManager.HEAD, root)); } + sw.report(); return refs; }