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;
}