diff --git a/community-resources/src/community_progress_tail.png b/community-resources/src/community_progress_tail.png index b6f7661c913c..96ef6a29a2b4 100644 Binary files a/community-resources/src/community_progress_tail.png and b/community-resources/src/community_progress_tail.png differ diff --git a/community-resources/src/idea/IdeaApplicationInfo.xml b/community-resources/src/idea/IdeaApplicationInfo.xml index 7617517167e7..b13f07f17d4c 100644 --- a/community-resources/src/idea/IdeaApplicationInfo.xml +++ b/community-resources/src/idea/IdeaApplicationInfo.xml @@ -3,7 +3,7 @@ - + diff --git a/community-resources/src/idea_community_logo.png b/community-resources/src/idea_community_logo.png index 4465f9545620..d70123f66651 100644 Binary files a/community-resources/src/idea_community_logo.png and b/community-resources/src/idea_community_logo.png differ diff --git a/community-resources/src/idea_community_logo@2x.png b/community-resources/src/idea_community_logo@2x.png index dc9a5a0af2de..4043de1d7cfe 100644 Binary files a/community-resources/src/idea_community_logo@2x.png and b/community-resources/src/idea_community_logo@2x.png differ diff --git a/java/compiler/impl/src/com/intellij/compiler/ant/GenerateAntApplication.java b/java/compiler/impl/src/com/intellij/compiler/ant/GenerateAntApplication.java index 5a2fa70ec801..b8a27b7818dc 100644 --- a/java/compiler/impl/src/com/intellij/compiler/ant/GenerateAntApplication.java +++ b/java/compiler/impl/src/com/intellij/compiler/ant/GenerateAntApplication.java @@ -23,8 +23,6 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectManagerEx; -import com.intellij.openapi.roots.impl.DirectoryIndex; -import com.intellij.openapi.roots.impl.DirectoryIndexImpl; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; @@ -81,9 +79,6 @@ public class GenerateAntApplication { logMessage(0, "Loading project..."); myProject = ProjectManagerEx.getInstanceEx().loadProject(myProjectPath); - DirectoryIndexImpl dirIndex = (DirectoryIndexImpl)DirectoryIndex.getInstance(myProject); - dirIndex.initialize(); - logMessageLn(0, " done"); GenerateAntBuildAction.generateSingleFileBuild(myProject, diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/method/MethodHierarchyNodeDescriptor.java b/java/java-impl/src/com/intellij/ide/hierarchy/method/MethodHierarchyNodeDescriptor.java index 3e0a0e164dd7..61e530339ffa 100644 --- a/java/java-impl/src/com/intellij/ide/hierarchy/method/MethodHierarchyNodeDescriptor.java +++ b/java/java-impl/src/com/intellij/ide/hierarchy/method/MethodHierarchyNodeDescriptor.java @@ -24,10 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ui.util.CompositeAppearance; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Iconable; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiModifier; +import com.intellij.psi.*; import com.intellij.psi.presentation.java.ClassPresentationUtil; import com.intellij.ui.LayeredIcon; import com.intellij.ui.RowIcon; @@ -41,13 +38,12 @@ public final class MethodHierarchyNodeDescriptor extends HierarchyNodeDescriptor private Icon myStateIcon; private MethodHierarchyTreeStructure myTreeStructure; - public MethodHierarchyNodeDescriptor( - final Project project, - final HierarchyNodeDescriptor parentDescriptor, - final PsiClass aClass, - final boolean isBase, - final MethodHierarchyTreeStructure treeStructure - ){ + public MethodHierarchyNodeDescriptor(final Project project, + final HierarchyNodeDescriptor parentDescriptor, + final PsiElement aClass, + final boolean isBase, + final MethodHierarchyTreeStructure treeStructure + ) { super(project, parentDescriptor, aClass, isBase); myTreeStructure = treeStructure; } @@ -60,24 +56,26 @@ public final class MethodHierarchyNodeDescriptor extends HierarchyNodeDescriptor return MethodHierarchyUtil.findBaseMethodInClass(myTreeStructure.getBaseMethod(), aClass, checkBases); } - public final PsiClass getPsiClass() { - return (PsiClass)myElement; + public final PsiElement getPsiClass() { + return myElement; } /** * Element for OpenFileDescriptor */ public final PsiElement getTargetElement() { - final PsiClass aClass = getPsiClass(); - if (aClass == null || !aClass.isValid()) return null; + final PsiElement element = getPsiClass(); + if (!(element instanceof PsiClass)) return element; + final PsiClass aClass = (PsiClass)getPsiClass(); + if (!aClass.isValid()) return null; final PsiMethod method = getMethod(aClass, false); if (method != null) return method; return aClass; } public final boolean isValid() { - final PsiClass aClass = getPsiClass(); - return aClass != null && aClass.isValid(); + final PsiElement psiElement = getPsiClass(); + return psiElement != null && psiElement.isValid(); } public final boolean update() { @@ -88,7 +86,7 @@ public final class MethodHierarchyNodeDescriptor extends HierarchyNodeDescriptor boolean changes = super.update(); - final PsiClass psiClass = getPsiClass(); + final PsiElement psiClass = getPsiClass(); if (psiClass == null){ final String invalidPrefix = IdeBundle.message("node.hierarchy.invalid"); @@ -99,7 +97,7 @@ public final class MethodHierarchyNodeDescriptor extends HierarchyNodeDescriptor } final Icon newRawIcon = psiClass.getIcon(flags); - final Icon newStateIcon = calculateState(psiClass); + final Icon newStateIcon = psiClass instanceof PsiClass ? calculateState((PsiClass)psiClass) : AllIcons.Hierarchy.MethodDefined; if (changes || newRawIcon != myRawIcon || newStateIcon != myStateIcon) { changes = true; @@ -133,8 +131,12 @@ public final class MethodHierarchyNodeDescriptor extends HierarchyNodeDescriptor if (myColor != null) { classNameAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN); } - myHighlightedText.getEnding().addText(ClassPresentationUtil.getNameForClass(psiClass, false), classNameAttributes); - myHighlightedText.getEnding().addText(" (" + JavaHierarchyUtil.getPackageName(psiClass) + ")", HierarchyNodeDescriptor.getPackageNameAttributes()); + if (psiClass instanceof PsiClass) { + myHighlightedText.getEnding().addText(ClassPresentationUtil.getNameForClass((PsiClass)psiClass, false), classNameAttributes); + myHighlightedText.getEnding().addText(" (" + JavaHierarchyUtil.getPackageName((PsiClass)psiClass) + ")", HierarchyNodeDescriptor.getPackageNameAttributes()); + } else if (psiClass instanceof PsiFunctionalExpression) { + myHighlightedText.getEnding().addText(ClassPresentationUtil.getFunctionalExpressionPresentation((PsiFunctionalExpression)psiClass, false)); + } myName = myHighlightedText.getText(); if (!Comparing.equal(myHighlightedText, oldText)) { diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/method/MethodHierarchyTreeStructure.java b/java/java-impl/src/com/intellij/ide/hierarchy/method/MethodHierarchyTreeStructure.java index acc90641d725..747bd2a039b1 100644 --- a/java/java-impl/src/com/intellij/ide/hierarchy/method/MethodHierarchyTreeStructure.java +++ b/java/java-impl/src/com/intellij/ide/hierarchy/method/MethodHierarchyTreeStructure.java @@ -21,6 +21,9 @@ import com.intellij.ide.hierarchy.HierarchyTreeStructure; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.search.searches.FunctionalExpressionSearch; +import com.intellij.util.ArrayUtil; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -152,11 +155,12 @@ public final class MethodHierarchyTreeStructure extends HierarchyTreeStructure { @NotNull @Override protected final Object[] buildChildren(@NotNull final HierarchyNodeDescriptor descriptor) { - final PsiClass psiClass = ((MethodHierarchyNodeDescriptor)descriptor).getPsiClass(); - + final PsiElement psiElement = ((MethodHierarchyNodeDescriptor)descriptor).getPsiClass(); + if (!(psiElement instanceof PsiClass)) return ArrayUtil.EMPTY_OBJECT_ARRAY; + final PsiClass psiClass = (PsiClass)psiElement; final Collection subclasses = getSubclasses(psiClass); - List descriptors = new ArrayList(subclasses.size()); + final List descriptors = new ArrayList(subclasses.size()); for (final PsiClass aClass : subclasses) { if (HierarchyBrowserManager.getInstance(myProject).getState().HIDE_CLASSES_WHERE_METHOD_NOT_IMPLEMENTED) { if (shouldHideClass(aClass)) { @@ -167,6 +171,15 @@ public final class MethodHierarchyTreeStructure extends HierarchyTreeStructure { final MethodHierarchyNodeDescriptor d = new MethodHierarchyNodeDescriptor(myProject, descriptor, aClass, false, this); descriptors.add(d); } + + FunctionalExpressionSearch.search(psiClass).forEach(new Processor() { + @Override + public boolean process(PsiFunctionalExpression expression) { + descriptors.add(new MethodHierarchyNodeDescriptor(myProject, descriptor, expression, false, MethodHierarchyTreeStructure.this)); + return true; + } + }); + return descriptors.toArray(new HierarchyNodeDescriptor[descriptors.size()]); } diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/method/OverrideImplementMethodAction.java b/java/java-impl/src/com/intellij/ide/hierarchy/method/OverrideImplementMethodAction.java index cf7ea89360ee..73504e6db865 100644 --- a/java/java-impl/src/com/intellij/ide/hierarchy/method/OverrideImplementMethodAction.java +++ b/java/java-impl/src/com/intellij/ide/hierarchy/method/OverrideImplementMethodAction.java @@ -68,7 +68,10 @@ abstract class OverrideImplementMethodAction extends AnAction { final ReadonlyStatusHandler.OperationStatus status = ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(VfsUtil.toVirtualFileArray(files)); if (!status.hasReadonlyFiles()) { for (HierarchyNodeDescriptor selectedDescriptor : selectedDescriptors) { - OverrideImplementUtil.overrideOrImplement(((MethodHierarchyNodeDescriptor)selectedDescriptor).getPsiClass(), methodHierarchyBrowser.getBaseMethod()); + final PsiElement aClass = ((MethodHierarchyNodeDescriptor)selectedDescriptor).getPsiClass(); + if (aClass instanceof PsiClass) { + OverrideImplementUtil.overrideOrImplement((PsiClass)aClass, methodHierarchyBrowser.getBaseMethod()); + } } ToolWindowManager.getInstance(project).activateEditorComponent(); } @@ -146,8 +149,10 @@ abstract class OverrideImplementMethodAction extends AnAction { protected abstract void update(Presentation presentation, int toImplement, int toOverride); private static boolean canImplementOverride(final MethodHierarchyNodeDescriptor descriptor, final MethodHierarchyBrowser methodHierarchyBrowser, final boolean toImplement) { - final PsiClass psiClass = descriptor.getPsiClass(); - if (psiClass == null || psiClass instanceof PsiSyntheticClass) return false; + final PsiElement psiElement = descriptor.getPsiClass(); + if (!(psiElement instanceof PsiClass)) return false; + final PsiClass psiClass = (PsiClass)psiElement; + if (psiClass instanceof PsiSyntheticClass) return false; final PsiMethod baseMethod = methodHierarchyBrowser.getBaseMethod(); if (baseMethod == null) return false; final MethodSignature signature = baseMethod.getSignature(PsiSubstitutor.EMPTY); diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/type/SubtypesHierarchyTreeStructure.java b/java/java-impl/src/com/intellij/ide/hierarchy/type/SubtypesHierarchyTreeStructure.java index 478ecd2e7a4b..dd104332c617 100644 --- a/java/java-impl/src/com/intellij/ide/hierarchy/type/SubtypesHierarchyTreeStructure.java +++ b/java/java-impl/src/com/intellij/ide/hierarchy/type/SubtypesHierarchyTreeStructure.java @@ -19,12 +19,12 @@ import com.intellij.ide.IdeBundle; import com.intellij.ide.hierarchy.HierarchyNodeDescriptor; import com.intellij.ide.hierarchy.HierarchyTreeStructure; import com.intellij.openapi.project.Project; -import com.intellij.psi.CommonClassNames; -import com.intellij.psi.PsiAnonymousClass; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiModifier; +import com.intellij.psi.*; +import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.util.ArrayUtil; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -45,17 +45,27 @@ public class SubtypesHierarchyTreeStructure extends HierarchyTreeStructure { @NotNull protected final Object[] buildChildren(@NotNull final HierarchyNodeDescriptor descriptor) { - final PsiClass psiClass = ((TypeHierarchyNodeDescriptor)descriptor).getPsiClass(); + final Object element = ((TypeHierarchyNodeDescriptor)descriptor).getPsiClass(); + if (!(element instanceof PsiClass)) return ArrayUtil.EMPTY_OBJECT_ARRAY; + final PsiClass psiClass = (PsiClass)element; if (CommonClassNames.JAVA_LANG_OBJECT.equals(psiClass.getQualifiedName())) { return new Object[]{IdeBundle.message("node.hierarchy.java.lang.object")}; } if (psiClass instanceof PsiAnonymousClass) return ArrayUtil.EMPTY_OBJECT_ARRAY; if (psiClass.hasModifierProperty(PsiModifier.FINAL)) return ArrayUtil.EMPTY_OBJECT_ARRAY; - final List classes = new ArrayList(ClassInheritorsSearch.search(psiClass, psiClass.getUseScope().intersectWith(getSearchScope(myCurrentScopeType, psiClass)), false).findAll()); - final HierarchyNodeDescriptor[] descriptors = new HierarchyNodeDescriptor[classes.size()]; - for (int i = 0; i < classes.size(); i++) { - descriptors[i] = new TypeHierarchyNodeDescriptor(myProject, descriptor, classes.get(i), false); + final SearchScope searchScope = psiClass.getUseScope().intersectWith(getSearchScope(myCurrentScopeType, psiClass)); + final List classes = new ArrayList(ClassInheritorsSearch.search(psiClass, searchScope, false).findAll()); + final List descriptors = new ArrayList(classes.size()); + for (PsiClass aClass : classes) { + descriptors.add(new TypeHierarchyNodeDescriptor(myProject, descriptor, aClass, false)); } - return descriptors; + FunctionalExpressionSearch.search(psiClass, searchScope).forEach(new Processor() { + @Override + public boolean process(PsiFunctionalExpression expression) { + descriptors.add(new TypeHierarchyNodeDescriptor(myProject, descriptor, expression, false)); + return true; + } + }); + return descriptors.toArray(new HierarchyNodeDescriptor[descriptors.size()]); } } diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/type/SupertypesHierarchyTreeStructure.java b/java/java-impl/src/com/intellij/ide/hierarchy/type/SupertypesHierarchyTreeStructure.java index fe7bb8287735..b5c6bf03ffe8 100644 --- a/java/java-impl/src/com/intellij/ide/hierarchy/type/SupertypesHierarchyTreeStructure.java +++ b/java/java-impl/src/com/intellij/ide/hierarchy/type/SupertypesHierarchyTreeStructure.java @@ -18,9 +18,9 @@ package com.intellij.ide.hierarchy.type; import com.intellij.ide.hierarchy.HierarchyNodeDescriptor; import com.intellij.ide.hierarchy.HierarchyTreeStructure; import com.intellij.openapi.project.Project; -import com.intellij.psi.CommonClassNames; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiClass; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -34,15 +34,24 @@ public final class SupertypesHierarchyTreeStructure extends HierarchyTreeStructu @NotNull protected final Object[] buildChildren(@NotNull final HierarchyNodeDescriptor descriptor) { - final PsiClass psiClass = ((TypeHierarchyNodeDescriptor)descriptor).getPsiClass(); - final PsiClass[] supers = psiClass.getSupers(); - final List descriptors = new ArrayList(); - PsiClass objectClass = JavaPsiFacade.getInstance(myProject).findClass(CommonClassNames.JAVA_LANG_OBJECT, psiClass.getResolveScope()); - for (PsiClass aSuper : supers) { - if (!psiClass.isInterface() || !aSuper.equals(objectClass)) { - descriptors.add(new TypeHierarchyNodeDescriptor(myProject, descriptor, aSuper, false)); + final Object element = ((TypeHierarchyNodeDescriptor)descriptor).getPsiClass(); + if (element instanceof PsiClass) { + final PsiClass psiClass = (PsiClass)element; + final PsiClass[] supers = psiClass.getSupers(); + final List descriptors = new ArrayList(); + final PsiClass objectClass = JavaPsiFacade.getInstance(myProject).findClass(CommonClassNames.JAVA_LANG_OBJECT, psiClass.getResolveScope()); + for (PsiClass aSuper : supers) { + if (!psiClass.isInterface() || !aSuper.equals(objectClass)) { + descriptors.add(new TypeHierarchyNodeDescriptor(myProject, descriptor, aSuper, false)); + } + } + return descriptors.toArray(new HierarchyNodeDescriptor[descriptors.size()]); + } else if (element instanceof PsiFunctionalExpression) { + final PsiClass functionalInterfaceClass = PsiUtil.resolveClassInType(((PsiFunctionalExpression)element).getFunctionalInterfaceType()); + if (functionalInterfaceClass != null) { + return new HierarchyNodeDescriptor[] {new TypeHierarchyNodeDescriptor(myProject, descriptor, functionalInterfaceClass, false)}; } } - return descriptors.toArray(new HierarchyNodeDescriptor[descriptors.size()]); + return ArrayUtil.EMPTY_OBJECT_ARRAY; } } diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/type/TypeHierarchyNodeDescriptor.java b/java/java-impl/src/com/intellij/ide/hierarchy/type/TypeHierarchyNodeDescriptor.java index 042326439e34..2351f6f0b42e 100644 --- a/java/java-impl/src/com/intellij/ide/hierarchy/type/TypeHierarchyNodeDescriptor.java +++ b/java/java-impl/src/com/intellij/ide/hierarchy/type/TypeHierarchyNodeDescriptor.java @@ -24,23 +24,25 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ui.util.CompositeAppearance; import com.intellij.openapi.util.Comparing; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFunctionalExpression; import com.intellij.psi.presentation.java.ClassPresentationUtil; import com.intellij.ui.LayeredIcon; import java.awt.*; public final class TypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor { - public TypeHierarchyNodeDescriptor(final Project project, final HierarchyNodeDescriptor parentDescriptor, final PsiClass psiClass, final boolean isBase) { - super(project, parentDescriptor, psiClass, isBase); + public TypeHierarchyNodeDescriptor(final Project project, final HierarchyNodeDescriptor parentDescriptor, final PsiElement classOrFunctionalExpression, final boolean isBase) { + super(project, parentDescriptor, classOrFunctionalExpression, isBase); } - public final PsiClass getPsiClass() { - return (PsiClass)myElement; + public final PsiElement getPsiClass() { + return myElement; } public final boolean isValid() { - final PsiClass aClass = getPsiClass(); - return aClass != null && aClass.isValid(); + final PsiElement psiElement = getPsiClass(); + return psiElement != null && psiElement.isValid(); } public final boolean update() { @@ -61,7 +63,7 @@ public final class TypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor { setIcon(icon); } - final PsiClass psiClass = getPsiClass(); + final PsiElement psiElement = getPsiClass(); final CompositeAppearance oldText = myHighlightedText; @@ -71,8 +73,12 @@ public final class TypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor { if (myColor != null) { classNameAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN); } - myHighlightedText.getEnding().addText(ClassPresentationUtil.getNameForClass(psiClass, false), classNameAttributes); - myHighlightedText.getEnding().addText(" (" + JavaHierarchyUtil.getPackageName(psiClass) + ")", HierarchyNodeDescriptor.getPackageNameAttributes()); + if (psiElement instanceof PsiClass) { + myHighlightedText.getEnding().addText(ClassPresentationUtil.getNameForClass((PsiClass)psiElement, false), classNameAttributes); + myHighlightedText.getEnding().addText(" (" + JavaHierarchyUtil.getPackageName((PsiClass)psiElement) + ")", HierarchyNodeDescriptor.getPackageNameAttributes()); + } else if (psiElement instanceof PsiFunctionalExpression) { + myHighlightedText.getEnding().addText(ClassPresentationUtil.getFunctionalExpressionPresentation(((PsiFunctionalExpression)psiElement), false)); + } myName = myHighlightedText.getText(); if (!Comparing.equal(myHighlightedText, oldText)) { diff --git a/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java b/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java index 99826b875b33..3b9e2496f125 100644 --- a/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java +++ b/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java @@ -26,11 +26,14 @@ import com.intellij.ide.util.TreeClassChooserFactory; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFunctionalExpression; import com.intellij.psi.presentation.java.ClassPresentationUtil; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.util.Processor; import org.jetbrains.annotations.Nullable; import java.util.LinkedList; @@ -59,11 +62,19 @@ public class ClassHierarchyScopeDescriptor extends ScopeDescriptor { PsiClass aClass = chooser.getSelected(); if (aClass == null) return null; - List classesToSearch = new LinkedList(); + final List classesToSearch = new LinkedList(); classesToSearch.add(aClass); classesToSearch.addAll(ClassInheritorsSearch.search(aClass, true).findAll()); + FunctionalExpressionSearch.search(aClass).forEach(new Processor() { + @Override + public boolean process(PsiFunctionalExpression expression) { + classesToSearch.add(expression); + return true; + } + }); + myCachedScope = new LocalSearchScope(PsiUtilCore.toPsiElementArray(classesToSearch), IdeBundle.message("scope.hierarchy", ClassPresentationUtil.getNameForClass(aClass, true))); } diff --git a/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java b/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java index 09d752f28adb..e61ba7af6426 100644 --- a/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java @@ -30,6 +30,7 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.javadoc.PsiDocTag; +import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.MethodSignatureUtil; @@ -48,6 +49,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.Processor; import com.intellij.util.containers.HashMap; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -456,6 +458,8 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { removeDeletedMethods(OverridingMethodsSearch.search(psiMethod, true).toArray(PsiMethod.EMPTY_ARRAY), allElementsToDelete); + findFunctionalExpressions(usages, ArrayUtil.prepend(psiMethod, overridingMethods)); + final HashMap> methodToReferences = new HashMap>(); for (PsiMethod overridingMethod : overridingMethods) { final Collection overridingReferences = ReferencesSearch.search(overridingMethod).findAll(); @@ -478,6 +482,19 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { }; } + private static void findFunctionalExpressions(final List usages, PsiMethod... methods) { + for (PsiMethod method : methods) { + final PsiClass containingClass = method.getContainingClass(); + FunctionalExpressionSearch.search(containingClass).forEach(new Processor() { + @Override + public boolean process(PsiFunctionalExpression expression) { + usages.add(new SafeDeleteFunctionalExpressionUsageInfo(expression, containingClass)); + return true; + } + }); + } + } + private static PsiMethod[] removeDeletedMethods(PsiMethod[] methods, final PsiElement[] allElementsToDelete) { ArrayList list = new ArrayList(); for (PsiMethod method : methods) { @@ -730,6 +747,8 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { return true; } }); + + findFunctionalExpressions(usages, method); } @@ -760,4 +779,13 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { return false; } + + private static class SafeDeleteFunctionalExpressionUsageInfo extends SafeDeleteReferenceUsageInfo { + public SafeDeleteFunctionalExpressionUsageInfo(@NotNull PsiElement element, PsiElement referencedElement) { + super(element, referencedElement, false); + } + + @Override + public void deleteElement() throws IncorrectOperationException {} + } } diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index ab112ebf0aa9..7c86ef988f62 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -22,7 +22,6 @@ import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.util.*; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,7 +34,6 @@ import java.util.*; public class LambdaUtil { public static ThreadLocal> ourFunctionTypes = new ThreadLocal>(); private static final Logger LOG = Logger.getInstance("#" + LambdaUtil.class.getName()); - @NonNls public static final String JAVA_LANG_FUNCTIONAL_INTERFACE = "java.lang.FunctionalInterface"; @Nullable public static PsiType getFunctionalInterfaceReturnType(PsiLambdaExpression expr) { @@ -434,7 +432,7 @@ public class LambdaUtil { @Nullable public static String checkFunctionalInterface(@NotNull PsiAnnotation annotation, @NotNull LanguageLevel languageLevel) { - if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && Comparing.strEqual(annotation.getQualifiedName(), JAVA_LANG_FUNCTIONAL_INTERFACE)) { + if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && Comparing.strEqual(annotation.getQualifiedName(), CommonClassNames.JAVA_LANG_FUNCTIONAL_INTERFACE)) { final PsiAnnotationOwner owner = annotation.getOwner(); if (owner instanceof PsiModifierList) { final PsiElement parent = ((PsiModifierList)owner).getParent(); diff --git a/java/java-psi-api/src/com/intellij/psi/PsiFunctionalExpression.java b/java/java-psi-api/src/com/intellij/psi/PsiFunctionalExpression.java index 30c8e0604549..e03806582884 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiFunctionalExpression.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiFunctionalExpression.java @@ -15,9 +15,10 @@ */ package com.intellij.psi; +import com.intellij.openapi.util.Iconable; import org.jetbrains.annotations.Nullable; -public interface PsiFunctionalExpression extends PsiExpression { +public interface PsiFunctionalExpression extends PsiExpression, Iconable { /** * @return SAM type the lambda expression corresponds to * null when no SAM type could be found diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java index 7bdd013b5792..069f667d92cf 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source.tree.java; +import com.intellij.icons.AllIcons; import com.intellij.lang.ASTNode; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; @@ -33,6 +34,8 @@ import com.intellij.util.containers.IntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; + public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements PsiLambdaExpression { public PsiLambdaExpressionImpl() { @@ -218,4 +221,10 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi } return paramType; } + + @Nullable + @Override + public Icon getIcon(int flags) { + return AllIcons.Nodes.AnonymousClass; + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java index 474d6bab62f9..7a82b2437a90 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source.tree.java; +import com.intellij.icons.AllIcons; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; @@ -41,6 +42,7 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.util.Map; public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase implements PsiMethodReferenceExpression { @@ -469,4 +471,10 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase } return false; } + + @Nullable + @Override + public Icon getIcon(int flags) { + return AllIcons.Nodes.AnonymousClass; + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/presentation/java/ClassPresentationUtil.java b/java/java-psi-impl/src/com/intellij/psi/presentation/java/ClassPresentationUtil.java index 2a13a0e98bb9..42171ad26d7e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/presentation/java/ClassPresentationUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/presentation/java/ClassPresentationUtil.java @@ -62,7 +62,7 @@ public class ClassPresentationUtil { } } - private static String getContextName(@NotNull PsiElement element, boolean qualified) { + public static String getContextName(@NotNull PsiElement element, boolean qualified) { PsiElement parent = PsiTreeUtil.getParentOfType(element, PsiMember.class, PsiFile.class); while(true){ if (parent == null) return null; @@ -72,4 +72,8 @@ public class ClassPresentationUtil { parent = parent.getParent(); } } + + public static String getFunctionalExpressionPresentation(PsiFunctionalExpression functionalExpression, boolean qualified) { + return "Functional expression in " + getContextName(functionalExpression, qualified); + } } diff --git a/java/java-tests/testData/refactoring/safeDelete/FunctionalInterfaceMethod.java b/java/java-tests/testData/refactoring/safeDelete/FunctionalInterfaceMethod.java new file mode 100644 index 000000000000..2f1c097726d0 --- /dev/null +++ b/java/java-tests/testData/refactoring/safeDelete/FunctionalInterfaceMethod.java @@ -0,0 +1,11 @@ +interface SAM { + void foo(int i); +} + +class Test { + + { + SAM sam = (i) -> {}; + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/safeDelete/ParameterFromFunctionalInterface.java b/java/java-tests/testData/refactoring/safeDelete/ParameterFromFunctionalInterface.java new file mode 100644 index 000000000000..61f666d0d856 --- /dev/null +++ b/java/java-tests/testData/refactoring/safeDelete/ParameterFromFunctionalInterface.java @@ -0,0 +1,11 @@ +interface SAM { + void foo(int i); +} + +class Test { + + { + SAM sam = (i) -> {}; + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java b/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java index a6768c98d0f3..610dd19bc4cb 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/SafeDeleteTest.java @@ -134,6 +134,30 @@ public class SafeDeleteTest extends MultiFileTestCase { } } + public void testParameterFromFunctionalInterface() throws Exception { + try { + LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_8); + doSingleFileTest(); + fail("Conflict was not detected"); + } + catch (BaseRefactoringProcessor.ConflictsInTestsException e) { + String message = e.getMessage(); + assertEquals("class SAM has 1 usage that is not safe to delete.", message); + } + } + + public void testFunctionalInterfaceMethod() throws Exception { + try { + LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_8); + doSingleFileTest(); + fail("Conflict was not detected"); + } + catch (BaseRefactoringProcessor.ConflictsInTestsException e) { + String message = e.getMessage(); + assertEquals("class SAM has 1 usage that is not safe to delete.", message); + } + } + public void testMethodDeepHierarchy() throws Exception { doTest("Super"); } diff --git a/platform/core-api/src/com/intellij/psi/CommonClassNames.java b/platform/core-api/src/com/intellij/psi/CommonClassNames.java index 32485e7a9066..8cfc405ed8eb 100644 --- a/platform/core-api/src/com/intellij/psi/CommonClassNames.java +++ b/platform/core-api/src/com/intellij/psi/CommonClassNames.java @@ -100,4 +100,5 @@ public interface CommonClassNames { @NonNls String JAVA_LANG_INVOKE_MH_POLYMORPHIC = "java.lang.invoke.MethodHandle.PolymorphicSignature"; @NonNls String CLASS_FILE_EXTENSION = ".class"; + @NonNls String JAVA_LANG_FUNCTIONAL_INTERFACE = "java.lang.FunctionalInterface"; } diff --git a/platform/icons/src/css/toolwindow.png b/platform/icons/src/css/toolwindow.png new file mode 100644 index 000000000000..c8f834244489 Binary files /dev/null and b/platform/icons/src/css/toolwindow.png differ diff --git a/platform/icons/src/css/toolwindow@2x.png b/platform/icons/src/css/toolwindow@2x.png new file mode 100644 index 000000000000..a4f7a13557c0 Binary files /dev/null and b/platform/icons/src/css/toolwindow@2x.png differ diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java index 460534c8ffed..c4de04196207 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java @@ -17,152 +17,84 @@ package com.intellij.openapi.roots.impl; import com.intellij.ProjectTopics; import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileTypes.FileTypeEvent; import com.intellij.openapi.fileTypes.FileTypeListener; import com.intellij.openapi.fileTypes.FileTypeManager; -import com.intellij.openapi.fileTypes.FileTypeRegistry; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.progress.EmptyProgressIndicator; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectBundle; -import com.intellij.openapi.roots.*; -import com.intellij.openapi.roots.impl.libraries.LibraryEx; -import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.util.*; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.*; -import com.intellij.openapi.vfs.impl.BulkVirtualFileListenerAdapter; +import com.intellij.openapi.roots.ModuleRootAdapter; +import com.intellij.openapi.roots.ModuleRootEvent; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.newvfs.BulkFileListener; -import com.intellij.openapi.vfs.newvfs.ManagingFS; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; -import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent; -import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent; import com.intellij.openapi.vfs.newvfs.events.VFileEvent; -import com.intellij.openapi.vfs.newvfs.impl.FileNameCache; -import com.intellij.util.*; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.MultiMap; -import com.intellij.util.containers.Stack; +import com.intellij.util.CollectionQuery; +import com.intellij.util.Query; import com.intellij.util.messages.MessageBusConnection; -import gnu.trove.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.jps.model.module.JpsModuleSourceRootType; -import java.util.*; +import java.util.List; public class DirectoryIndexImpl extends DirectoryIndex { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.DirectoryIndexImpl"); - private static final boolean CHECK = ApplicationManager.getApplication().isUnitTestMode(); - private static final TObjectHashingStrategy INT_ARRAY_STRATEGY = new TObjectHashingStrategy() { - @Override - public int computeHashCode(int[] object) { - return Arrays.hashCode(object); - } - @Override - public boolean equals(int[] o1, int[] o2) { - return Arrays.equals(o1, o2); - } - }; - - private final ManagingFS myPersistence; private final Project myProject; private final MessageBusConnection myConnection; - private final DirectoryIndexExcludePolicy[] myExcludePolicies; - private volatile IndexState myState = new IndexState(); - private volatile boolean myInitialized = false; private volatile boolean myDisposed = false; - private final PackageSink mySink = new PackageSink(); - private static final boolean ourUseRootIndexOnly = Registry.is("directory.index.use.root.index"); - private static final boolean ourCompareImplementations = Registry.is("directory.index.compare.implementations"); private volatile RootIndex myRootIndex = null; - public DirectoryIndexImpl(@NotNull ManagingFS managingFS, @NotNull Project project, @NotNull StartupManager startupManager) { - myPersistence = managingFS; + public DirectoryIndexImpl(@NotNull Project project) { myProject = project; myConnection = project.getMessageBus().connect(project); - myExcludePolicies = Extensions.getExtensions(DirectoryIndexExcludePolicy.EP_NAME, myProject); - if (ourUseRootIndexOnly) { - initialize(); - } else { - startupManager.registerPreStartupActivity(new Runnable() { - @Override - public void run() { - initialize(); - } - }); - } + subscribeToFileChanges(); + markContentRootsForRefresh(); Disposer.register(project, new Disposable() { @Override public void dispose() { myDisposed = true; - myState.multiDirPackages.clear(); - myState.myDirToInfoMap.clear(); - myState.myDirToPackageName.clear(); - myState.myExcludeRootsMap.clear(); - myState.myPackageNameToDirsMap.clear(); - myState.myProjectExcludeRoots.clear(); - myState.myRootTypeId.clear(); - myState.myRootTypes.clear(); myRootIndex = null; } }); } - public void initialize() { - subscribeToFileChanges(); - - if (myInitialized) { - LOG.error("Directory index is already initialized."); - return; - } - - if (myDisposed) { - LOG.error("Directory index is already disposed for this project"); - return; - } - - myInitialized = true; - long l = System.currentTimeMillis(); - doInitialize(); - LOG.info("Directory index initialized in " + - (System.currentTimeMillis() - l) + - " ms, indexed " + - myState.myDirToInfoMap.size() + - " directories"); - - markContentRootsForRefresh(); - } - private void subscribeToFileChanges() { myConnection.subscribe(FileTypeManager.TOPIC, new FileTypeListener.Adapter() { @Override public void fileTypesChanged(@NotNull FileTypeEvent event) { - doInitialize(); + myRootIndex = null; } }); myConnection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() { @Override public void rootsChanged(ModuleRootEvent event) { - doInitialize(); + myRootIndex = null; } }); - myConnection.subscribe(VirtualFileManager.VFS_CHANGES, new MyVirtualFileListener()); + myConnection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { + @Override + public void before(@NotNull List events) { + } + + @Override + public void after(@NotNull List events) { + RootIndex rootIndex = myRootIndex; + if (rootIndex != null && rootIndex.resetOnEvents(events)) { + myRootIndex = null; + } + } + }); } private void markContentRootsForRefresh() { @@ -181,304 +113,14 @@ public class DirectoryIndexImpl extends DirectoryIndex { myConnection.deliverImmediately(); } - private class MyVirtualFileListener extends VirtualFileAdapter implements BulkFileListener { - @Override - public void fileCreated(@NotNull VirtualFileEvent event) { - VirtualFile file = event.getFile(); - - if (!file.isDirectory()) return; - - VirtualFile parent = file.getParent(); - if (!(parent instanceof NewVirtualFile)) return; - DirectoryInfo existing = myState.getInfo(((NewVirtualFile)file).getId()); - assert existing == null : file + " -> " + existing; - IndexState newState = updateStateWithNewFile((NewVirtualFile)file, (NewVirtualFile)parent); - replaceState(newState); - } - - @NotNull - private IndexState updateStateWithNewFile(@NotNull NewVirtualFile file, @NotNull NewVirtualFile parent) { - final IndexState originalState = myState; - IndexState state = originalState; - int parentId = parent.getId(); - DirectoryInfo parentInfo = originalState.getInfo(parentId); - if (parentInfo != null) { - assertAncestor(parentInfo, parent, parentId); - } - - // fill info for all nested roots - String fileUrl = file.getUrl(); - for (Module eachModule : ModuleManager.getInstance(myProject).getModules()) { - for (ContentEntry contentRoot : getContentEntries(eachModule)) { - if (parentInfo != null) { - VirtualFile contFile = contentRoot.getFile(); - if (contFile != null && contFile.equals(parentInfo.getContentRoot())) continue; - } - - String contentRootUrl = contentRoot.getUrl(); - if (FileUtil.startsWith(contentRootUrl, fileUrl)) { - String rel = FileUtil.getRelativePath(fileUrl, contentRootUrl, '/'); - if (rel != null) { - VirtualFile f = file.findFileByRelativePath(rel); - if (f instanceof NewVirtualFile) { - if (state == originalState) state = state.copy(null); - state.fillMapWithModuleContent((NewVirtualFile)f, eachModule, (NewVirtualFile)f, null); - } - } - } - } - } - - for (DirectoryIndexExcludePolicy policy : myExcludePolicies) { - if (policy.isExcludeRoot(file)) { - if (parentInfo == null || parentInfo.getContentRoot() == null) { - if (state == originalState) state = state.copy(null); - state.myProjectExcludeRoots.add(file.getId()); - } - return state; - } - } - - if (parentInfo == null) return state; - Module module = parentInfo.getModule(); - - if (state == originalState) state = state.copy(null); - VirtualFile parentContentRoot = parentInfo.getContentRoot(); - state.fillMapWithModuleContent(file, module, (NewVirtualFile)parentContentRoot, null); - - String parentPackage = state.getPackageNameForDirectory(parent); - TObjectIntHashMap interned = new TObjectIntHashMap(); - - if (module != null) { - if (parentInfo.isInModuleSource()) { - String newDirPackageName = getPackageNameForSubdir(parentPackage, file.getName()); - state.fillMapWithModuleSource(module, (NewVirtualFile)parentContentRoot, file, newDirPackageName, - (NewVirtualFile)parentInfo.getSourceRoot(), parentInfo.getSourceRootTypeId(), null, interned); - } - } - - if (parentInfo.hasLibraryClassRoot()) { - String newDirPackageName = getPackageNameForSubdir(parentPackage, file.getName()); - state.fillMapWithLibraryClasses(file, newDirPackageName, (NewVirtualFile)parentInfo.getLibraryClassRoot(), null, interned, null); - } - - if (parentInfo.isInLibrarySource()) { - String newDirPackageName = getPackageNameForSubdir(parentPackage, file.getName()); - state.fillMapWithLibrarySources(file, newDirPackageName, (NewVirtualFile)parentInfo.getSourceRoot(), null, interned, null); - } - - OrderEntry[] entries = parentInfo.getOrderEntries(); - if (entries.length != 0) { - state.fillMapWithOrderEntries(file, entries, null, null, null, parentInfo, null); - } - return state; - } - - private final Key FILES_TO_RELEASE_KEY = Key.create("DirectoryIndexImpl.MyVirtualFileListener.FILES_TO_RELEASE_KEY"); - - @Override - public void beforeFileDeletion(@NotNull VirtualFileEvent event) { - VirtualFile file = event.getFile(); - if (!file.isDirectory()) return; - if (myState.getInfo(((NewVirtualFile)file).getId()) == null) return; - - TIntArrayList list = new TIntArrayList(); - addDirsRecursively(myState, list, file); - file.putUserData(FILES_TO_RELEASE_KEY, list.toNativeArray()); - } - - private void addDirsRecursively(@NotNull IndexState state, @NotNull TIntArrayList list, @NotNull VirtualFile dir) { - if (!(dir instanceof NewVirtualFile)) return; - int id = ((NewVirtualFile)dir).getId(); - if (state.getInfo(id) == null) return; - - list.add(id); - - for (VirtualFile child : ((NewVirtualFile)dir).getCachedChildren()) { - if (child.isDirectory()) { - addDirsRecursively(state, list, child); - } - } - } - - @Override - public void fileDeleted(@NotNull VirtualFileEvent event) { - VirtualFile file = event.getFile(); - final int[] list = file.getUserData(FILES_TO_RELEASE_KEY); - if (list == null) return; - - IndexState copy = null; - for (int id : list) { - if (myState.getInfo(id) != null) { - if (copy == null) { - copy = myState.copy(new TIntProcedure() { - @Override - public boolean execute(int fid) { - return ArrayUtil.indexOf(list, fid) == -1; - } - }); - } - - copy.myDirToInfoMap.remove(id); - copy.setPackageName(id, null); - } - } - - if (copy != null) { - replaceState(copy); - } - myState.assertAncestorsConsistent(); - } - - @Override - public void fileMoved(@NotNull VirtualFileMoveEvent event) { - VirtualFile file = event.getFile(); - if (file.isDirectory()) { - doInitialize(); - } - myState.assertAncestorsConsistent(); - } - - @Override - public void propertyChanged(@NotNull VirtualFilePropertyEvent event) { - if (VirtualFile.PROP_NAME.equals(event.getPropertyName())) { - VirtualFile file = event.getFile(); - if (file.isDirectory()) { - doInitialize(); - } - } - myState.assertAncestorsConsistent(); - } - - private boolean myBatchChangePlanned; - - @Override - public void before(@NotNull List events) { - if (ourUseRootIndexOnly) { - return; - } - - myBatchChangePlanned = false; - final boolean willDoBatchUpdate = isLargeVfsChange(events); - if (willDoBatchUpdate) { - myBatchChangePlanned = true; - LOG.info("will rebuild index state"); - } - else { - for (VFileEvent event : events) { - BulkVirtualFileListenerAdapter.fireBefore(this, event); - } - } - } - - @Override - public void after(@NotNull List events) { - RootIndex rootIndex = myRootIndex; - if (rootIndex != null && rootIndex.resetOnEvents(events)) { - myRootIndex = null; - } - if (ourUseRootIndexOnly) { - return; - } - - if (myBatchChangePlanned) { - myBatchChangePlanned = false; - long started = System.currentTimeMillis(); - doInitialize(); - LOG.info("Rebuilt indexstate for " + (System.currentTimeMillis() - started)); - } - else { - for (VFileEvent event : events) { - BulkVirtualFileListenerAdapter.fireAfter(this, event); - } - } - } - } - - private void replaceState(IndexState newState) { - newState.writable = false; - myState = newState; - } - - private class PackageSink extends QueryFactory>> { - private final Condition IS_VALID = new Condition() { - @Override - public boolean value(final VirtualFile virtualFile) { - return virtualFile.isValid(); - } - }; - - private PackageSink() { - registerExecutor(new QueryExecutor>>() { - @Override - public boolean execute(@NotNull final Pair> stateAndDirs, - @NotNull final Processor consumer) { - for (VirtualFile dir : stateAndDirs.second) { - DirectoryInfo info = stateAndDirs.first.myDirToInfoMap.get(((NewVirtualFile)dir).getId()); - assert info != null; - - if (!info.isInLibrarySource() || info.isInModuleSource() || info.hasLibraryClassRoot()) { - if (!consumer.process(dir)) return false; - } - } - return true; - } - }); - } - - public Query search(@NotNull String packageName, boolean includeLibrarySources) { - checkAvailability(); - dispatchPendingEvents(); - - IndexState state = myState; - int[] allDirs = state.getDirsForPackage(internPackageName(packageName, null)); - if (allDirs == null) allDirs = ArrayUtil.EMPTY_INT_ARRAY; - - List files = new ArrayList(allDirs.length); - for (int dir : allDirs) { - VirtualFile file = findFileById(dir); - if (file != null) { - files.add(file); - } - } - - Query query = includeLibrarySources ? new CollectionQuery(files) : createQuery(Pair.create(state, files)); - return new FilteredQuery(query, IS_VALID); - } - } - @Override @NotNull public Query getDirectoriesByPackageName(@NotNull String packageName, boolean includeLibrarySources) { - - RootIndex rootIndex = getRootIndex(); - if (rootIndex != null) { - Collection riResult = rootIndex.getDirectoriesByPackageName(packageName, includeLibrarySources); - if (ourUseRootIndexOnly) { - return new CollectionQuery(riResult); - } - - Query standardResult = mySink.search(packageName, includeLibrarySources); - Collection standard = standardResult.findAll(); - if (!new HashSet(riResult).equals(new HashSet(standard))) { - for (VirtualFile file : standard) { - String path = file.getPath(); - if (path.substring(path.length() - packageName.length()).contains(".")) { - return standardResult; // standard and rootIndex return different results for directories with dot in name - } - } - assertConsistentResult(packageName, riResult, standard); - } - } - - return mySink.search(packageName, includeLibrarySources); + return new CollectionQuery(getRootIndex().getDirectoriesByPackageName(packageName, includeLibrarySources)); } - @Nullable + @NotNull private RootIndex getRootIndex() { - if (!ourUseRootIndexOnly && !ourCompareImplementations) { - return null; - } RootIndex rootIndex = myRootIndex; if (rootIndex == null) { myRootIndex = rootIndex = new RootIndex(myProject); @@ -489,97 +131,12 @@ public class DirectoryIndexImpl extends DirectoryIndex { @Override @TestOnly public void checkConsistency() { - RootIndex rootIndex = getRootIndex(); - if (rootIndex != null) { - rootIndex.checkConsistency(); - } - if (ourUseRootIndexOnly) { - return; - } - - doCheckConsistency(false); - doCheckConsistency(true); - } - - @TestOnly - public void assertAncestorConsistent() { - myState.assertAncestorsConsistent(); - } - - @TestOnly - private void doCheckConsistency(boolean reverseAllSets) { - assert myInitialized; - assert !myDisposed; - myState.assertNotWritable(); - - final IndexState oldState = myState; - myState.assertAncestorsConsistent(); - replaceState(myState.copy(null)); - myState.writable = true; - - myState.doInitialize(reverseAllSets); - myState.writable = false; - - int[] keySet = myState.myDirToInfoMap.keys(); - assert keySet.length == oldState.myDirToInfoMap.keys().length; - for (int file : keySet) { - DirectoryInfo info1 = myState.getInfo(file); - DirectoryInfo info2 = oldState.getInfo(file); - assert info1 != null; - assert info1.equals(info2); - info1.assertConsistency(); - } - - assert myState.myPackageNameToDirsMap.size() == oldState.myPackageNameToDirsMap.size(); - myState.myPackageNameToDirsMap.forEachEntry(new TObjectIntProcedure() { - @Override - public boolean execute(int[] packageName, int i) { - int[] dirs = oldState.getDirsForPackage(packageName); - int[] dirs1 = myState.getDirsForPackage(packageName); - - TIntHashSet set1 = new TIntHashSet(dirs); - TIntHashSet set2 = new TIntHashSet(dirs1); - assert set1.equals(set2); - return true; - } - }); + getRootIndex().checkConsistency(); } @Override public boolean isInitialized() { - return myInitialized; - } - - private void doInitialize() { - myRootIndex = null; - if (ourUseRootIndexOnly) { - return; - } - - IndexState newState = new IndexState(); - newState.doInitialize(false); - replaceState(newState); - } - - private boolean isExcludeRootForModule(@NotNull Module module, VirtualFile excludeRoot) { - for (DirectoryIndexExcludePolicy policy : myExcludePolicies) { - if (policy.isExcludeRootForModule(module, excludeRoot)) return true; - } - return false; - } - - @NotNull - private static ContentEntry[] getContentEntries(@NotNull Module module) { - return ModuleRootManager.getInstance(module).getContentEntries(); - } - - @NotNull - private static OrderEntry[] getOrderEntries(@NotNull Module module) { - return ModuleRootManager.getInstance(module).getOrderEntries(); - } - - private static boolean isIgnored(@NotNull VirtualFile f) { - return FileTypeRegistry.getInstance().isFileIgnored(f); + return true; } @Override @@ -589,61 +146,14 @@ public class DirectoryIndexImpl extends DirectoryIndex { if (!(dir instanceof NewVirtualFile)) return null; - RootIndex rootIndex = getRootIndex(); - DirectoryInfo riInfo = rootIndex != null ? rootIndex.getInfoForDirectory(dir) : null; - if (ourUseRootIndexOnly) { - return riInfo; - } - - DirectoryInfo standardResult = myState.getInfo(((NewVirtualFile)dir).getId()); - assertConsistentResult(dir, riInfo, standardResult); - if (standardResult != riInfo && standardResult.equals(riInfo) && rootIndex != null) { - rootIndex.cacheInfos(dir, dir, standardResult); - } - return standardResult; - } - - private T assertConsistentResult(@NotNull Object arg, @Nullable T rootIndexResult, T standardResult) { - //noinspection ConstantConditions - if (ourCompareImplementations && !Comparing.equal(rootIndexResult, standardResult)) { - String msg = "DirectoryIndex differs from RootIndex at " + arg + - "\nriInfo = " + rootIndexResult + - "\nstandardResult = " + standardResult + - "\nRoot model:"; - for (Module module : ModuleManager.getInstance(myProject).getModules()) { - msg += "\nModule " + module.getName(); - for (ContentEntry entry : ModuleRootManager.getInstance(module).getContentEntries()) { - msg += "\n Content " + entry.getFile(); - for (VirtualFile file : entry.getSourceFolderFiles()) { - msg += "\n Source " + file; - } - for (VirtualFile file : entry.getExcludeFolderFiles()) { - msg += "\n Excluded " + file; - } - } - } - for (DirectoryIndexExcludePolicy policy : Extensions.getExtensions(DirectoryIndexExcludePolicy.EP_NAME, myProject)) { - for (VirtualFile root : policy.getExcludeRootsForProject()) { - msg += "\nProject exclude " + root; - } - } - - LOG.error(msg); - } - return standardResult; + return getRootIndex().getInfoForDirectory(dir); } @Override @Nullable public JpsModuleSourceRootType getSourceRootType(@NotNull DirectoryInfo info) { if (info.isInModuleSource()) { - RootIndex rootIndex = getRootIndex(); - JpsModuleSourceRootType riType = rootIndex != null ? rootIndex.getSourceRootType(info) : null; - if (ourUseRootIndexOnly) { - return riType; - } - - return assertConsistentResult(info, riType, myState.getRootTypeById(info.getSourceRootTypeId())); + return getRootIndex().getSourceRootType(info); } return null; } @@ -653,19 +163,7 @@ public class DirectoryIndexImpl extends DirectoryIndex { checkAvailability(); if (!(dir instanceof NewVirtualFile)) return false; - if (ourUseRootIndexOnly) { - //noinspection ConstantConditions - return getRootIndex().isProjectExcludeRoot(dir); - } - - //noinspection UnnecessaryLocalVariable - boolean standardResult = myState.myProjectExcludeRoots.contains(((NewVirtualFile)dir).getId()); -/* - RootIndex rootIndex = getRootIndex(); - Boolean riResult = rootIndex != null ? rootIndex.isProjectExcludeRoot(dir) : null; - assertConsistentResult(dir, riResult, standardResult); -*/ - return standardResult; + return getRootIndex().isProjectExcludeRoot(dir); } @Override @@ -673,17 +171,7 @@ public class DirectoryIndexImpl extends DirectoryIndex { checkAvailability(); if (!(dir instanceof NewVirtualFile)) return false; - if (ourUseRootIndexOnly) { - //noinspection ConstantConditions - return getRootIndex().isModuleExcludeRoot(dir); - } - - // unsupported with old indexing - return false; - } - - private VirtualFile findFileById(int dir) { - return myPersistence.findFileById(dir); + return getRootIndex().isModuleExcludeRoot(dir); } @Override @@ -691,1004 +179,14 @@ public class DirectoryIndexImpl extends DirectoryIndex { checkAvailability(); if (!(dir instanceof NewVirtualFile)) return null; - RootIndex rootIndex = getRootIndex(); - String riResult = rootIndex != null ? rootIndex.getPackageName(dir) : null; - if (ourUseRootIndexOnly) { - return riResult; - } - - return assertConsistentResult(dir, riResult, myState.getPackageNameForDirectory((NewVirtualFile)dir)); - } - - private static String decodePackageName(@NotNull int[] interned) { - if (interned.length == 0) { - return ""; - } - - StringBuilder result = new StringBuilder(interned[0]); - for (int i = 1; i < interned.length; i++) { - if (i > 1) { - result.append('.'); - } - result.append(FileNameCache.getVFileName(interned[i])); - } - return result.toString(); - } - - private static int[] internPackageName(@Nullable String packageName, @Nullable TObjectIntHashMap alreadyEnumerated) { - if (packageName == null) { - return null; - } - - if (packageName.isEmpty()) { - return ArrayUtil.EMPTY_INT_ARRAY; - } - - int dotCount = StringUtil.countChars(packageName, '.'); - int[] result = new int[dotCount + 2]; - result[0] = packageName.length(); - - int tokenStart = 0; - int tokenIndex = 0; - while (tokenStart < packageName.length()) { - int tokenEnd = packageName.indexOf('.', tokenStart); - if (tokenEnd < 0) { - tokenEnd = packageName.length(); - } - String nextName = packageName.substring(tokenStart, tokenEnd); - int internedId = alreadyEnumerated != null ? alreadyEnumerated.get(nextName) : 0; - if (internedId == 0) { - internedId = FileNameCache.storeName(nextName); - if (alreadyEnumerated != null) alreadyEnumerated.put(nextName, internedId); - } - result[tokenIndex + 1] = internedId; - tokenStart = tokenEnd + 1; - tokenIndex++; - } - return result; + return getRootIndex().getPackageName(dir); } private void checkAvailability() { - if (!myInitialized) { - LOG.error("Directory index is not initialized yet for " + myProject); - } - if (myDisposed) { ProgressManager.checkCanceled(); LOG.error("Directory index is already disposed for " + myProject); } } - @Nullable - private static String getPackageNameForSubdir(String parentPackageName, String subdirName) { - if (parentPackageName == null) return null; - return parentPackageName.isEmpty() ? subdirName : parentPackageName + "." + subdirName; - } - - private class IndexState { - private final TIntObjectHashMap> myExcludeRootsMap = new TIntObjectHashMap>(); - private final TIntHashSet myProjectExcludeRoots = new TIntHashSet(); - private final TIntObjectHashMap myDirToInfoMap = new TIntObjectHashMap(); - private final TObjectIntHashMap myPackageNameToDirsMap = new TObjectIntHashMap(INT_ARRAY_STRATEGY); - private final List multiDirPackages = new ArrayList(Arrays.asList(new int[]{-1})); - private final TIntObjectHashMap myDirToPackageName = new TIntObjectHashMap(); - private final TObjectIntHashMap> myRootTypeId = new TObjectIntHashMap>(); - private final List> myRootTypes = new ArrayList>(); - private volatile boolean writable = true; - - private IndexState() { - } - - @Nullable - private int[] getDirsForPackage(@NotNull int[] packageName) { - assertNotWritable(); - int i = myPackageNameToDirsMap.get(packageName); - return i == 0 ? null : i > 0 ? new int[]{i} : multiDirPackages.get(-i); - } - - private void removeDirFromPackage(@NotNull int[] packageName, int dirId) { - assertWritable(); - int i = myPackageNameToDirsMap.get(packageName); - int[] oldPackageDirs = i == 0 ? null : i > 0 ? new int[]{i} : multiDirPackages.get(-i); - assert oldPackageDirs != null; - int index = ArrayUtil.find(oldPackageDirs, dirId); - assert index != -1; - oldPackageDirs = ArrayUtil.remove(oldPackageDirs, index); - - if (oldPackageDirs.length == 0) { - myPackageNameToDirsMap.remove(packageName); - if (i < 0) { - multiDirPackages.set(-i, null); - } - } - else { - assert i < 0 : i; - multiDirPackages.set(-i, oldPackageDirs); - } - } - - private void addDirToPackage(@NotNull int[] packageName, int dirId) { - assertWritable(); - assert dirId > 0; - - int i = myPackageNameToDirsMap.get(packageName); - - if (i < 0) { - // add another dir to the list of existing dirs - int[] ids = multiDirPackages.get(-i); - int[] newIds = ids == null ? new int[]{dirId} : ArrayUtil.append(ids, dirId); - multiDirPackages.set(-i, newIds); - } - else if (i > 0) { - // two dirs instead of one - int newIndex = multiDirPackages.size(); - multiDirPackages.add(new int[]{i, dirId}); - myPackageNameToDirsMap.put(packageName, -newIndex); - } - else { - // create new dir mapping - myPackageNameToDirsMap.put(packageName, dirId); - } - } - - @NotNull - private DirectoryInfo getOrCreateDirInfo(int dirId) { - DirectoryInfo info = getInfo(dirId); - if (info == null) { - info = DirectoryInfo.createNew(); - storeInfo(info, dirId); - } - return info; - } - - @Nullable - private DirectoryInfo getInfo(int fileId) { - return myDirToInfoMap.get(fileId); - } - - private void storeInfo(@NotNull DirectoryInfo info, int id) { - assertWritable(); - if (CHECK) { - VirtualFile file = findFileById(id); - VirtualFile contentRoot = info.getContentRoot(); - if (file != null && contentRoot != null) { - assert VfsUtilCore.isAncestor(contentRoot, file, false) : "File: "+file+"; Content root: "+contentRoot; - } - } - assert id > 0 : id; - myDirToInfoMap.put(id, info); - } - - private void assertAncestorsConsistent() { - if (CHECK) { - myDirToInfoMap.forEachEntry(new TIntObjectProcedure() { - @Override - public boolean execute(int id, DirectoryInfo info) { - VirtualFile file = findFileById(id); - if (file == null) { - return true; - } - VirtualFile contentRoot = info.getContentRoot(); - if (contentRoot != null) { - assertAncestor(info, contentRoot, id); - } - VirtualFile sourceRoot = info.getSourceRoot(); - if (sourceRoot != null) { - assertAncestor(info, sourceRoot, id); - - if (contentRoot != null) { - assert VfsUtilCore.isAncestor(contentRoot, sourceRoot, false) : contentRoot + ";" + sourceRoot; - } - } - return true; - } - }); - } - } - - private void fillMapWithModuleContent(@NotNull NewVirtualFile root, - final Module module, - final NewVirtualFile contentRoot, - @Nullable final ProgressIndicator progress) { - assertWritable(); - if (!isValid(root)) return; - final int contentRootId = contentRoot == null ? 0 : contentRoot.getId(); - if (contentRoot != null) { - assert VfsUtilCore.isAncestor(contentRoot, root, false) : "Root: "+root+"; contentRoot: "+contentRoot; - } - VfsUtilCore.visitChildrenRecursively(root, new DirectoryVisitor() { - @Override - protected DirectoryInfo updateInfo(@NotNull VirtualFile file) { - if (progress != null) { - progress.checkCanceled(); - } - if (isExcluded(contentRootId, file)) return null; - if (isIgnored(file)) return null; - - DirectoryInfo info = getOrCreateDirInfo(((NewVirtualFile)file).getId()); - - if (info.getModule() != null) { // module contents overlap - VirtualFile dir = file.getParent(); - DirectoryInfo parentInfo = dir == null ? null : getInfo(((NewVirtualFile)dir).getId()); - if (parentInfo == null || !info.getModule().equals(parentInfo.getModule())) return null; - } - - return info; - } - - @Override - protected void afterChildrenVisited(@NotNull VirtualFile file, @NotNull DirectoryInfo info) { - with(((NewVirtualFile)file).getId(), info, module, contentRoot, null, null, 0, null); - } - }); - } - - @NotNull - private DirectoryInfo with(int id, - @NotNull DirectoryInfo info, - Module module, - VirtualFile contentRoot, - VirtualFile sourceRoot, - VirtualFile libraryClassRoot, - int sourceRootTypeData, - OrderEntry[] orderEntries) { - if (contentRoot != null) { - assertAncestor(info, contentRoot, id); - } - if (sourceRoot instanceof NewVirtualFile) { - VirtualFile root = contentRoot == null ? info.getContentRoot() : contentRoot; - if (root != null) { - assertAncestor(info, root, ((NewVirtualFile)sourceRoot).getId()); - } - } - DirectoryInfo newInfo = info.with(module, contentRoot, sourceRoot, libraryClassRoot, sourceRootTypeData, orderEntries); - storeInfo(newInfo, id); - return newInfo; - } - - @Nullable - private String getPackageNameForDirectory(NewVirtualFile dir) { - int[] interned = myDirToPackageName.get(dir.getId()); - return interned == null ? null : decodePackageName(interned); - } - - private abstract class DirectoryVisitor extends VirtualFileVisitor { - private final Stack myDirectoryInfoStack = new Stack(); - - @Override - public boolean visitFile(@NotNull VirtualFile file) { - if (!file.isDirectory()) return false; - DirectoryInfo info = updateInfo(file); - if (info != null) { - myDirectoryInfoStack.push(info); - return true; - } - return false; - } - - @Override - public void afterChildrenVisited(@NotNull VirtualFile file) { - afterChildrenVisited(file, myDirectoryInfoStack.pop()); - } - - @Nullable - protected abstract DirectoryInfo updateInfo(@NotNull VirtualFile file); - - protected void afterChildrenVisited(@NotNull VirtualFile file, @NotNull DirectoryInfo info) {} - } - - private boolean isExcluded(int root, @NotNull VirtualFile dir) { - if (root == 0) return false; - Set excludes = myExcludeRootsMap.get(root); - return excludes != null && excludes.contains(dir.getUrl()); - } - - private void initModuleContents(@NotNull Module module, boolean reverseAllSets, @NotNull ProgressIndicator progress) { - assertWritable(); - progress.checkCanceled(); - progress.setText2(ProjectBundle.message("project.index.processing.module.content.progress", module.getName())); - - ModuleRootManager rootManager = ModuleRootManager.getInstance(module); - VirtualFile[] contentRoots = rootManager.getContentRoots(); - if (reverseAllSets) { - contentRoots = ArrayUtil.reverseArray(contentRoots); - } - - for (final VirtualFile contentRoot : contentRoots) { - if (contentRoot instanceof NewVirtualFile) { - fillMapWithModuleContent((NewVirtualFile)contentRoot, module, (NewVirtualFile)contentRoot, progress); - } - } - } - - private void initModuleSources(@NotNull Module module, boolean reverseAllSets, @NotNull ProgressIndicator progress, - @Nullable TObjectIntHashMap interned) { - assertWritable(); - progress.checkCanceled(); - progress.setText2(ProjectBundle.message("project.index.processing.module.sources.progress", module.getName())); - - ContentEntry[] contentEntries = getContentEntries(module); - - if (reverseAllSets) { - contentEntries = ArrayUtil.reverseArray(contentEntries); - } - - for (ContentEntry contentEntry : contentEntries) { - VirtualFile contentRoot = contentEntry.getFile(); - SourceFolder[] sourceFolders = contentEntry.getSourceFolders(); - if (reverseAllSets) { - sourceFolders = ArrayUtil.reverseArray(sourceFolders); - } - for (SourceFolder sourceFolder : sourceFolders) { - VirtualFile dir = sourceFolder.getFile(); - if (dir instanceof NewVirtualFile && contentRoot instanceof NewVirtualFile) { - int rootTypeId = getRootTypeId(sourceFolder); - fillMapWithModuleSource(module, (NewVirtualFile)contentRoot, (NewVirtualFile)dir, sourceFolder.getPackagePrefix(), - (NewVirtualFile)dir, rootTypeId, progress, interned); - } - } - } - } - - private int getRootTypeId(@NotNull SourceFolder sourceFolder) { - JpsModuleSourceRootType rootType = sourceFolder.getRootType(); - if (myRootTypeId.containsKey(rootType)) { - return myRootTypeId.get(rootType); - } - - int id = myRootTypes.size(); - if (id > DirectoryInfo.MAX_ROOT_TYPE_ID) { - LOG.error("Too many different types of module source roots (" + id + ") registered: " + myRootTypes); - } - myRootTypes.add(rootType); - myRootTypeId.put(rootType, id); - return id; - } - - @Nullable - private JpsModuleSourceRootType getRootTypeById(int id) { - if (id >= myRootTypes.size()) return null; - return myRootTypes.get(id); - } - - private void fillMapWithModuleSource(@NotNull final Module module, - @NotNull final NewVirtualFile contentRoot, - @NotNull final NewVirtualFile dir, - @NotNull final String packageName, - @NotNull final NewVirtualFile sourceRoot, - final int rootTypeId, - @Nullable final ProgressIndicator progress, - final @Nullable TObjectIntHashMap interned) { - assertWritable(); - if (!isValid(dir)) return; - assert VfsUtilCore.isAncestor(sourceRoot, dir, false) : - "SourceRoot: "+sourceRoot+" ("+sourceRoot.getFileSystem()+"); dir: "+dir+" ("+dir.getFileSystem()+")"; - VfsUtilCore.visitChildrenRecursively(dir, new DirectoryVisitor() { - private final Stack myPackages = new Stack(); - - @Override - protected DirectoryInfo updateInfo(@NotNull VirtualFile file) { - if (progress != null) { - progress.checkCanceled(); - } - int id = ((NewVirtualFile)file).getId(); - DirectoryInfo info = getInfo(id); - if (info == null) return null; - if (!module.equals(info.getModule())) return null; - if (!contentRoot.equals(info.getContentRoot())) return null; - - if (info.isInModuleSource()) { // module sources overlap - if (isAnotherRoot(id)) return null; // another source root starts here - } - - assert VfsUtilCore.isAncestor(dir, file, false) : - "dir: " + dir + " (" + dir.getFileSystem() + "); file: " + file + " (" + file.getFileSystem() + ")"; - - int flag = DirectoryInfo.createSourceRootTypeData(true, info.isInLibrarySource(), rootTypeId); - info = with(id, info, null, null, sourceRoot, null, flag, null); - - String currentPackage = myPackages.isEmpty() ? packageName : getPackageNameForSubdir(myPackages.peek(), file.getName()); - myPackages.push(currentPackage); - setPackageName(id, internPackageName(currentPackage, interned)); - return info; - } - - @Override - protected void afterChildrenVisited(@NotNull VirtualFile file, @NotNull DirectoryInfo info) { - super.afterChildrenVisited(file, info); - myPackages.pop(); - } - }); - } - - private boolean isAnotherRoot(int id) { - return myDirToPackageName.get(id) == ArrayUtil.EMPTY_INT_ARRAY; - } - - private void initLibrarySources(@NotNull Module module, - @NotNull ProgressIndicator progress, - @Nullable TObjectIntHashMap interned, - Map libraryExcludedRoots) { - assertWritable(); - progress.checkCanceled(); - progress.setText2(ProjectBundle.message("project.index.processing.library.sources.progress", module.getName())); - - for (OrderEntry orderEntry : getOrderEntries(module)) { - if (orderEntry instanceof LibraryOrSdkOrderEntry) { - VirtualFile[] sourceRoots = ((LibraryOrSdkOrderEntry)orderEntry).getRootFiles(OrderRootType.SOURCES); - TIntHashSet excludedRoots = getExcludedRootsOfLibrary((LibraryOrSdkOrderEntry)orderEntry, libraryExcludedRoots); - for (final VirtualFile sourceRoot : sourceRoots) { - if (sourceRoot instanceof NewVirtualFile) { - fillMapWithLibrarySources((NewVirtualFile)sourceRoot, "", (NewVirtualFile)sourceRoot, progress, interned, excludedRoots); - } - } - } - } - } - - private void fillMapWithLibrarySources(@NotNull final NewVirtualFile dir, - @Nullable final String packageName, - @NotNull final NewVirtualFile sourceRoot, - @Nullable final ProgressIndicator progress, - @Nullable final TObjectIntHashMap interned, - @Nullable final TIntHashSet excludedRoots) { - assertWritable(); - if (!isValid(dir)) return; - VfsUtilCore.visitChildrenRecursively(dir, new VirtualFileVisitor() { - { setValueForChildren(packageName); } - - @Override - public boolean visitFile(@NotNull VirtualFile file) { - if (progress != null) progress.checkCanceled(); - int dirId = ((NewVirtualFile)file).getId(); - if (!file.isDirectory() && dirId != dir.getId() || isIgnored(file)) return false; - if (excludedRoots != null && excludedRoots.contains(dirId)) return false; - DirectoryInfo info = getOrCreateDirInfo(dirId); - - if (info.isInLibrarySource()) { // library sources overlap - if (isAnotherRoot(dirId)) return false; // another library source root starts here - } - - int data = DirectoryInfo.createSourceRootTypeData(info.isInModuleSource(), true, info.getSourceRootTypeId()); - with(dirId, info, null, null, sourceRoot, null, data, null); - - final String packageName = getCurrentValue(); - final String newPackageName = Comparing.equal(file, dir) ? packageName : getPackageNameForSubdir(packageName, file.getName()); - setPackageName(dirId, internPackageName(newPackageName, interned)); - setValueForChildren(newPackageName); - - return true; - } - }); - } - - private void initLibraryClasses(@NotNull Module module, - @NotNull ProgressIndicator progress, - @Nullable TObjectIntHashMap interned, - @Nullable Map libraryExcludedRoots) { - assertWritable(); - progress.checkCanceled(); - progress.setText2(ProjectBundle.message("project.index.processing.library.classes.progress", module.getName())); - - for (OrderEntry orderEntry : getOrderEntries(module)) { - if (orderEntry instanceof LibraryOrSdkOrderEntry) { - VirtualFile[] classRoots = ((LibraryOrSdkOrderEntry)orderEntry).getRootFiles(OrderRootType.CLASSES); - TIntHashSet excludedRoots = getExcludedRootsOfLibrary((LibraryOrSdkOrderEntry)orderEntry, libraryExcludedRoots); - for (final VirtualFile classRoot : classRoots) { - if (classRoot instanceof NewVirtualFile) { - fillMapWithLibraryClasses((NewVirtualFile)classRoot, "", (NewVirtualFile)classRoot, progress, interned, excludedRoots); - } - } - } - } - } - - private void fillMapWithLibraryClasses(@NotNull final NewVirtualFile dir, - @NotNull final String packageName, - @NotNull final NewVirtualFile classRoot, - @Nullable final ProgressIndicator progress, - @Nullable final TObjectIntHashMap interned, - final TIntHashSet excludedRoots) { - assertWritable(); - if (!isValid(dir)) return; - VfsUtilCore.visitChildrenRecursively(dir, new VirtualFileVisitor() { - { setValueForChildren(packageName); } - - @Override - public boolean visitFile(@NotNull VirtualFile file) { - if (progress != null) progress.checkCanceled(); - if (!file.isDirectory() && !Comparing.equal(file, dir) || isIgnored(file)) return false; - - int dirId = ((NewVirtualFile)file).getId(); - if (excludedRoots != null && excludedRoots.contains(dirId)) return false; - DirectoryInfo info = getOrCreateDirInfo(dirId); - - if (info.hasLibraryClassRoot()) { // library classes overlap - if (isAnotherRoot(dirId)) return false; // another library root starts here - } - - info = with(dirId, info, null, null, null, classRoot, 0, null); - - final String packageName = getCurrentValue(); - final String childPackageName = Comparing.equal(file, dir) ? packageName : getPackageNameForSubdir(packageName, file.getName()); - if (!info.isInModuleSource() && !info.isInLibrarySource()) { - setPackageName(dirId, internPackageName(childPackageName, interned)); - } - setValueForChildren(childPackageName); - - return true; - } - }); - } - - @Nullable - private TIntHashSet getExcludedRootsOfLibrary(LibraryOrSdkOrderEntry orderEntry, Map libraryExcludedRoots) { - if (orderEntry instanceof LibraryOrderEntry) { - Library library = ((LibraryOrderEntry)orderEntry).getLibrary(); - if (library != null) { - TIntHashSet cached = libraryExcludedRoots.get(library); - if (cached != null) return cached; - - VirtualFile[] files = ((LibraryEx)library).getExcludedRoots(); - if (files.length > 0) { - TIntHashSet set = new TIntHashSet(); - for (VirtualFile file : files) { - if (file instanceof NewVirtualFile) { - set.add(((NewVirtualFile)file).getId()); - } - } - libraryExcludedRoots.put(library, set); - return set; - } - } - } - return null; - } - - private void initOrderEntries(@NotNull Module module, - @NotNull MultiMap depEntries, - @NotNull MultiMap libClassRootEntries, - @NotNull MultiMap libSourceRootEntries, - @NotNull ProgressIndicator progress) { - assertWritable(); - for (OrderEntry orderEntry : getOrderEntries(module)) { - if (orderEntry instanceof ModuleOrderEntry) { - final Module depModule = ((ModuleOrderEntry)orderEntry).getModule(); - if (depModule != null) { - VirtualFile[] importedClassRoots = - OrderEnumerator.orderEntries(depModule).exportedOnly().recursively().classes().usingCache().getRoots(); - for (VirtualFile importedClassRoot : importedClassRoots) { - depEntries.putValue(importedClassRoot, orderEntry); - } - } - VirtualFile[] sourceRoots = orderEntry.getFiles(OrderRootType.SOURCES); - for (VirtualFile sourceRoot : sourceRoots) { - depEntries.putValue(sourceRoot, orderEntry); - } - } - else if (orderEntry instanceof ModuleSourceOrderEntry) { - OrderEntry[] oneEntryList = {orderEntry}; - Module entryModule = orderEntry.getOwnerModule(); - - VirtualFile[] sourceRoots = ((ModuleSourceOrderEntry)orderEntry).getRootModel().getSourceRoots(); - for (VirtualFile sourceRoot : sourceRoots) { - if (sourceRoot instanceof NewVirtualFile) { - fillMapWithOrderEntries((NewVirtualFile)sourceRoot, oneEntryList, entryModule, null, null, null, progress); - } - } - } - else if (orderEntry instanceof LibraryOrSdkOrderEntry) { - final LibraryOrSdkOrderEntry entry = (LibraryOrSdkOrderEntry)orderEntry; - VirtualFile[] classRoots = entry.getRootFiles(OrderRootType.CLASSES); - for (VirtualFile classRoot : classRoots) { - libClassRootEntries.putValue(classRoot, orderEntry); - } - VirtualFile[] sourceRoots = entry.getRootFiles(OrderRootType.SOURCES); - for (VirtualFile sourceRoot : sourceRoots) { - libSourceRootEntries.putValue(sourceRoot, orderEntry); - } - } - } - } - - private void fillMapWithOrderEntries(@NotNull MultiMap depEntries, - @NotNull MultiMap libClassRootEntries, - @NotNull MultiMap libSourceRootEntries, - @NotNull ProgressIndicator progress) { - assertWritable(); - for (Map.Entry> mapEntry : depEntries.entrySet()) { - VirtualFile vRoot = mapEntry.getKey(); - Collection entries = mapEntry.getValue(); - if (vRoot instanceof NewVirtualFile) { - fillMapWithOrderEntries((NewVirtualFile)vRoot, toSortedArray(entries), null, null, null, null, progress); - } - } - - for (Map.Entry> mapEntry : libClassRootEntries.entrySet()) { - final VirtualFile vRoot = mapEntry.getKey(); - final Collection entries = mapEntry.getValue(); - if (vRoot instanceof NewVirtualFile) { - fillMapWithOrderEntries((NewVirtualFile)vRoot, toSortedArray(entries), null, (NewVirtualFile)vRoot, null, null, progress); - } - } - - for (Map.Entry> mapEntry : libSourceRootEntries.entrySet()) { - final VirtualFile vRoot = mapEntry.getKey(); - final Collection entries = mapEntry.getValue(); - if (vRoot instanceof NewVirtualFile) { - fillMapWithOrderEntries((NewVirtualFile)vRoot, toSortedArray(entries), null, null, (NewVirtualFile)vRoot, null, progress); - } - } - } - - private void setPackageName(int dirId, @Nullable int[] newPackageName) { - assertWritable(); - int[] oldPackageName = myDirToPackageName.get(dirId); - if (oldPackageName != null) { - removeDirFromPackage(oldPackageName, dirId); - } - - if (newPackageName == null) { - myDirToPackageName.remove(dirId); - } - else { - addDirToPackage(newPackageName, dirId); - - myDirToPackageName.put(dirId, newPackageName); - } - } - - // orderEntries must be sorted BY_OWNER_MODULE - private void fillMapWithOrderEntries(@NotNull final NewVirtualFile root, - @NotNull final OrderEntry[] orderEntries, - @Nullable final Module module, - @Nullable final NewVirtualFile libraryClassRoot, - @Nullable final NewVirtualFile librarySourceRoot, - @Nullable final DirectoryInfo parentInfo, - @Nullable final ProgressIndicator progress) { - assertWritable(); - if (!isValid(root)) return; - VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor() { - private final Stack myEntries = new Stack(); - - @Override - public boolean visitFile(@NotNull VirtualFile file) { - if (progress != null) { - progress.checkCanceled(); - } - if (!file.isDirectory() && !file.equals(root) || isIgnored(file)) return false; - - int fileId = ((NewVirtualFile)file).getId(); - DirectoryInfo info = getInfo(fileId); // do not create it here! - if (info == null) return false; - - if (module != null) { - if (info.getModule() != module || !info.isInModuleSource()) return false; - } - else if (libraryClassRoot != null) { - if (!libraryClassRoot.equals(info.getLibraryClassRoot()) || info.isInModuleSource()) return false; - } - else if (librarySourceRoot != null) { - if (!info.isInLibrarySource() - || !librarySourceRoot.equals(info.getSourceRoot()) - || info.hasLibraryClassRoot()) return false; - } - - OrderEntry[] oldParentEntries = myEntries.isEmpty() ? null : myEntries.peek(); - OrderEntry[] oldEntries = info.getOrderEntries(); - myEntries.push(oldEntries); - - OrderEntry[] newOrderEntries = info.calcNewOrderEntries(orderEntries, parentInfo, oldParentEntries); - with(fileId, info, null, null, null, null, 0, newOrderEntries); - - return true; - } - - @Override - public void afterChildrenVisited(@NotNull VirtualFile file) { - myEntries.pop(); - } - }); - } - - private void doInitialize(boolean reverseAllSets/* for testing order independence*/) { - assertWritable(); - assertAncestorsConsistent(); - ProgressIndicator progress = ProgressIndicatorProvider.getGlobalProgressIndicator(); - if (progress == null) progress = new EmptyProgressIndicator(); - - progress.pushState(); - - progress.checkCanceled(); - progress.setText(ProjectBundle.message("project.index.scanning.files.progress")); - - Module[] modules = ModuleManager.getInstance(myProject).getModules(); - if (reverseAllSets) modules = ArrayUtil.reverseArray(modules); - - initExcludedDirMap(modules, progress); - - for (Module module : modules) { - initModuleContents(module, reverseAllSets, progress); - } - - TObjectIntHashMap interned = new TObjectIntHashMap(100); - - // Important! Because module's contents may overlap, - // first modules should be marked and only after that sources markup - // should be added. (src markup depends on module markup) - IdentityHashMap libraryExcludedRoots = new IdentityHashMap(); - for (Module module : modules) { - initModuleSources(module, reverseAllSets, progress, interned); - initLibrarySources(module, progress, interned, libraryExcludedRoots); - initLibraryClasses(module, progress , interned, libraryExcludedRoots); - } - - progress.checkCanceled(); - progress.setText2(""); - - assertAncestorsConsistent(); - MultiMap depEntries = new MultiMap(); - MultiMap libClassRootEntries = new MultiMap(); - MultiMap libSourceRootEntries = new MultiMap(); - for (Module module : modules) { - initOrderEntries(module, depEntries, libClassRootEntries, libSourceRootEntries, progress); - } - fillMapWithOrderEntries(depEntries, libClassRootEntries, libSourceRootEntries, progress); - - internDirectoryInfos(); - progress.popState(); - } - - private void internDirectoryInfos() { - assertWritable(); - final Map diInterner = new THashMap(); - final Map oeInterner = new THashMap(new TObjectHashingStrategy() { - @Override - public int computeHashCode(OrderEntry[] object) { - return Arrays.hashCode(object); - } - - @Override - public boolean equals(OrderEntry[] o1, OrderEntry[] o2) { - return Arrays.equals(o1, o2); - } - }); - - assertAncestorsConsistent(); - myDirToInfoMap.transformValues(new TObjectFunction() { - @Override - public DirectoryInfo execute(DirectoryInfo info) { - DirectoryInfo interned = diInterner.get(info); - if (interned == null) { - OrderEntry[] entries = info.getOrderEntries(); - OrderEntry[] internedEntries = oeInterner.get(entries); - if (internedEntries == null) { - oeInterner.put(entries, entries); - } - else if (internedEntries != entries) { - info = info.withInternedEntries(internedEntries); - } - diInterner.put(info, interned = info); - } - return interned; - } - }); - assertAncestorsConsistent(); - } - - private void initExcludedDirMap(@NotNull Module[] modules, ProgressIndicator progress) { - assertWritable(); - progress.checkCanceled(); - progress.setText2(ProjectBundle.message("project.index.building.exclude.roots.progress")); - - // exclude roots should be merged to prevent including excluded dirs of an inner module into the outer - // exclude root should exclude from its content root and all outer content roots - - for (Module module : modules) { - for (ContentEntry contentEntry : getContentEntries(module)) { - VirtualFile contentRoot = contentEntry.getFile(); - if (!(contentRoot instanceof NewVirtualFile)) continue; - - for (VirtualFile excludeRoot : contentEntry.getExcludeFolderFiles()) { - // Output paths should be excluded (if marked as such) regardless if they're under corresponding module's content root - if (excludeRoot instanceof NewVirtualFile) { - if (!FileUtil.startsWith(excludeRoot.getUrl(), contentRoot.getUrl())) { - if (isExcludeRootForModule(module, excludeRoot)) { - putForFileAndAllAncestors((NewVirtualFile)excludeRoot, excludeRoot.getUrl()); - } - myProjectExcludeRoots.add(((NewVirtualFile)excludeRoot).getId()); - } - } - - } - for (String url : contentEntry.getExcludeFolderUrls()) { - putForFileAndAllAncestors((NewVirtualFile)contentRoot, url); - } - } - } - - for (DirectoryIndexExcludePolicy policy : myExcludePolicies) { - for (VirtualFile file : policy.getExcludeRootsForProject()) { - if (file instanceof NewVirtualFile) { - putForFileAndAllAncestors((NewVirtualFile)file, file.getUrl()); - myProjectExcludeRoots.add(((NewVirtualFile)file).getId()); - } - } - } - } - - private void putForFileAndAllAncestors(NewVirtualFile file, String value) { - assertWritable(); - TIntObjectHashMap > map = myExcludeRootsMap; - while (file != null) { - int id = file.getId(); - Set set = map.get(id); - if (set == null) { - set = new THashSet(); - map.put(id, set); - } - set.add(value); - - file = file.getParent(); - } - } - - private void assertWritable() { - assert writable; - } - - private void assertNotWritable() { - assert !writable; - } - - @NotNull - private IndexState copy(@Nullable final TIntProcedure idFilter) { - assertNotWritable(); - final IndexState copy = new IndexState(); - - myExcludeRootsMap.forEachEntry(new TIntObjectProcedure>() { - @Override - public boolean execute(int id, Set urls) { - if (idFilter == null || idFilter.execute(id)) { - copy.myExcludeRootsMap.put(id, new THashSet(urls)); - } - return true; - } - }); - - copy.myProjectExcludeRoots.addAll(myProjectExcludeRoots.toArray()); - myDirToInfoMap.forEachEntry(new TIntObjectProcedure() { - @Override - public boolean execute(int id, DirectoryInfo info) { - if (idFilter == null || idFilter.execute(id)) { - copy.storeInfo(info, id); - } - return true; - } - }); - - - copy.multiDirPackages.clear(); - for (int[] dirs : multiDirPackages) { - if (dirs == null) { - dirs = ArrayUtil.EMPTY_INT_ARRAY; - } - int[] filtered = ContainerUtil.filter(dirs, new TIntProcedure() { - @Override - public boolean execute(int id) { - return id == -1 || copy.getInfo(id) != null && (idFilter == null || idFilter.execute(id)); - } - }); - copy.multiDirPackages.add(filtered); - } - myPackageNameToDirsMap.forEachEntry(new TObjectIntProcedure() { - @Override - public boolean execute(int[] name, int id) { - if (id > 0) { - if (copy.getInfo(id) == null) id = 0; - } - else if (id < 0) { - if (copy.multiDirPackages.get(-id).length == 0) id = 0; - } - if (id != 0 && (idFilter == null || idFilter.execute(id))) { - copy.myPackageNameToDirsMap.put(name, id); - } - return true; - } - }); - - myDirToPackageName.forEachEntry(new TIntObjectProcedure() { - @Override - public boolean execute(int id, int[] name) { - if (idFilter == null || idFilter.execute(id)) { - copy.myDirToPackageName.put(id, name); - } - return true; - } - }); - - copy.myRootTypes.addAll(myRootTypes); - myRootTypeId.forEachEntry(new TObjectIntProcedure>() { - @Override - public boolean execute(JpsModuleSourceRootType root, int id) { - copy.myRootTypeId.put(root, id); - return true; - } - }); - - return copy; - } - } - - private static boolean isValid(@NotNull NewVirtualFile root) { - return root.getId() > 0; - } - - @NotNull - private static OrderEntry[] toSortedArray(@NotNull Collection entries) { - if (entries.isEmpty()) { - return OrderEntry.EMPTY_ARRAY; - } - OrderEntry[] result = entries.toArray(new OrderEntry[entries.size()]); - Arrays.sort(result, DirectoryInfo.BY_OWNER_MODULE); - return result; - } - - private void assertAncestor(@NotNull DirectoryInfo info, @NotNull VirtualFile root, int myId) { - VirtualFile myFile = findFileById(myId); - assert myFile.getFileSystem() == root.getFileSystem() : - myFile.getFileSystem() + ", " + root.getFileSystem() + "; my file: " + myFile + "; root: " + root + "; " + - myFile.getParent().getPath().equals(root.getPath()); - assert VfsUtilCore.isAncestor(root, myFile, false) : - "my file: " + myFile + " (" + ((NewVirtualFile)myFile).getId() + ")" + myFile.getClass() + " - " + System.identityHashCode(myFile) + - "; root: " + root + " (" + ((NewVirtualFile)root).getId() + ")" + root.getClass() + " - " + System.identityHashCode(root) + - "; equalsToParent:" + (myFile.getParent() == null ? "" : myFile.getParent().getPath()).equals(root.getPath()) + - "; equalsToRoot:" + myFile.equals(root) + - "; equalsToRootPath:" + myFile.getPath().equals(root.getPath()) + - "; my contentRoot: " + info.getContentRoot() + - "; my sourceRoot: " + info.getSourceRoot() + - "; my classRoot: " + info.getLibraryClassRoot() + - "; path is substring: " + FileUtil.isAncestor(root.getPath(), myFile.getPath(), false) - ; - } - - private static final int MAX_DEPTH_TO_COUNT = 20; - private static final int DIRECTORIES_CHANGED_THRESHOLD = 50; - - public static boolean isLargeVfsChange(List events) { - int directoriesRemoved = 0; - int directoriesCreated = 0; - - for (VFileEvent event : events) { - if (event instanceof VFileDeleteEvent) { - VirtualFile file = event.getFile(); - if (file != null && file.isDirectory()) { - directoriesRemoved += 1 + countDirectories(file, MAX_DEPTH_TO_COUNT); - } - } - else if (event instanceof VFileCreateEvent) { - VirtualFile file = event.getFile(); - if (file != null && file.isDirectory() || - file == null && ((VFileCreateEvent)event).isDirectory()) { - directoriesCreated += 1 + countDirectories(file, MAX_DEPTH_TO_COUNT); - } - } - } - - boolean largeChange = directoriesCreated + directoriesRemoved > DIRECTORIES_CHANGED_THRESHOLD; - if (largeChange) { - LOG.info("Too many directories created / deleted: " + directoriesCreated + "," + directoriesRemoved); - } - return largeChange; - } - - private static int countDirectories(@Nullable VirtualFile file, int depth) { - if (!(file instanceof NewVirtualFile)) return 0; - - int counter = 0; - for (VirtualFile child : ((NewVirtualFile)file).iterInDbChildren()) { - if (child.isDirectory()) counter += 1 + (depth > 0 ? countDirectories(child, depth - 1) : 0); - } - return counter; - } } diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/changes/VcsEventWatcher.java b/platform/lang-impl/src/com/intellij/openapi/vcs/changes/VcsEventWatcher.java index d4c374de6bc3..d38bb29f5043 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/changes/VcsEventWatcher.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/changes/VcsEventWatcher.java @@ -23,7 +23,6 @@ import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootAdapter; import com.intellij.openapi.roots.ModuleRootEvent; -import com.intellij.openapi.roots.impl.DirectoryIndex; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.problems.WolfTheProblemSolver; import com.intellij.util.messages.MessageBusConnection; @@ -47,7 +46,7 @@ public class VcsEventWatcher extends AbstractProjectComponent { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { - if (myProject.isDisposed() || !DirectoryIndex.getInstance(myProject).isInitialized()) return; + if (myProject.isDisposed()) return; VcsDirtyScopeManager.getInstance(myProject).markEverythingDirty(); } }, ModalityState.NON_MODAL); diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/CodeAnalysisBeforeCheckinHandler.java b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/CodeAnalysisBeforeCheckinHandler.java index c4d63dad1cfa..b19b62ce4af1 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/CodeAnalysisBeforeCheckinHandler.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/CodeAnalysisBeforeCheckinHandler.java @@ -67,7 +67,7 @@ public class CodeAnalysisBeforeCheckinHandler extends CheckinHandler { public JComponent getComponent() { JPanel panel = new JPanel(new BorderLayout()); panel.add(checkBox); - refreshEnable(checkBox); + TodoCheckinHandler.disableWhenDumb(myProject, checkBox, "Code analysis is impossible until indices are up-to-date"); return panel; } @@ -87,16 +87,6 @@ public class CodeAnalysisBeforeCheckinHandler extends CheckinHandler { }; } - private void refreshEnable(JCheckBox checkBox) { - if (DumbService.getInstance(myProject).isDumb()) { - checkBox.setEnabled(false); - checkBox.setToolTipText("Code analysis is impossible until indices are up-to-date"); - } else { - checkBox.setEnabled(true); - checkBox.setToolTipText(""); - } - } - private VcsConfiguration getSettings() { return VcsConfiguration.getInstance(myProject); } diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/OptimizeImportsBeforeCheckinHandler.java b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/OptimizeImportsBeforeCheckinHandler.java index 332004af5985..351623822b16 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/OptimizeImportsBeforeCheckinHandler.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/OptimizeImportsBeforeCheckinHandler.java @@ -19,6 +19,7 @@ package com.intellij.openapi.vcs.checkin; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.actions.OptimizeImportsProcessor; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.CheckinProjectPanel; import com.intellij.openapi.vcs.VcsBundle; @@ -47,7 +48,7 @@ public class OptimizeImportsBeforeCheckinHandler extends CheckinHandler implemen @Nullable public RefreshableOnComponent getBeforeCheckinConfigurationPanel() { final JCheckBox optimizeBox = new JCheckBox(VcsBundle.message("checkbox.checkin.options.optimize.imports")); - + TodoCheckinHandler.disableWhenDumb(myProject, optimizeBox, "Impossible until indices are up-to-date"); return new RefreshableOnComponent() { @Override public JComponent getComponent() { @@ -90,7 +91,7 @@ public class OptimizeImportsBeforeCheckinHandler extends CheckinHandler implemen } }; - if (configuration.OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT) { + if (configuration.OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT && !DumbService.isDumb(myProject)) { new OptimizeImportsProcessor(myProject, BeforeCheckinHandlerUtil.getPsiFiles(myProject, files), COMMAND_NAME, performCheckoutAction).run(); } else { finishAction.run(); diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/RearrangeBeforeCheckinHandler.java b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/RearrangeBeforeCheckinHandler.java index 1c19685fffff..481fa99beb27 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/RearrangeBeforeCheckinHandler.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/RearrangeBeforeCheckinHandler.java @@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.checkin; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.actions.RearrangeCodeProcessor; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.CheckinProjectPanel; import com.intellij.openapi.vcs.VcsBundle; @@ -44,7 +45,7 @@ public class RearrangeBeforeCheckinHandler extends CheckinHandler implements Che @Nullable public RefreshableOnComponent getBeforeCheckinConfigurationPanel() { final JCheckBox rearrangeBox = new JCheckBox(VcsBundle.message("checkbox.checkin.options.rearrange.code")); - + TodoCheckinHandler.disableWhenDumb(myProject, rearrangeBox, "Impossible until indices are up-to-date"); return new RefreshableOnComponent() { @Override public JComponent getComponent() { @@ -83,7 +84,7 @@ public class RearrangeBeforeCheckinHandler extends CheckinHandler implements Che } }; - if (VcsConfiguration.getInstance(myProject).REARRANGE_BEFORE_PROJECT_COMMIT) { + if (VcsConfiguration.getInstance(myProject).REARRANGE_BEFORE_PROJECT_COMMIT && !DumbService.isDumb(myProject)) { new RearrangeCodeProcessor( myProject, BeforeCheckinHandlerUtil.getPsiFiles(myProject, myPanel.getVirtualFiles()), COMMAND_NAME, performCheckoutAction ).run(); diff --git a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandler.java b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandler.java index 560760b4d76d..9464f78c5cb3 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandler.java +++ b/platform/lang-impl/src/com/intellij/openapi/vcs/checkin/TodoCheckinHandler.java @@ -26,7 +26,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; @@ -47,6 +46,7 @@ import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -64,7 +64,6 @@ public class TodoCheckinHandler extends CheckinHandler { private final CheckinProjectPanel myCheckinProjectPanel; private final VcsConfiguration myConfiguration; private TodoFilter myTodoFilter; - private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.checkin.TodoCheckinHandler"); public TodoCheckinHandler(CheckinProjectPanel checkinProjectPanel) { myProject = checkinProjectPanel.getProject(); @@ -105,7 +104,7 @@ public class TodoCheckinHandler extends CheckinHandler { }, null); panel.add(linkLabel, BorderLayout.CENTER); - refreshEnable(checkBox); + disableWhenDumb(myProject, checkBox, "TODO check is impossible until indices are up-to-date"); return panel; } @@ -133,14 +132,10 @@ public class TodoCheckinHandler extends CheckinHandler { }; } - private void refreshEnable(JCheckBox checkBox) { - if (DumbService.getInstance(myProject).isDumb()) { - checkBox.setEnabled(false); - checkBox.setToolTipText("TODO check is impossible until indices are up-to-date"); - } else { - checkBox.setEnabled(true); - checkBox.setToolTipText(""); - } + static void disableWhenDumb(@NotNull Project project, @NotNull JCheckBox checkBox, @NotNull String tooltip) { + boolean dumb = DumbService.isDumb(project); + checkBox.setEnabled(!dumb); + checkBox.setToolTipText(dumb ? tooltip : ""); } @Override diff --git a/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java b/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java index c6f410f35737..c8f6e69e5521 100644 --- a/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java +++ b/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java @@ -27,7 +27,10 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.ui.StripeTable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.JBColor; import com.intellij.ui.components.JBScrollPane; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.ui.ColorIcon; import com.intellij.util.ui.PlatformColors; @@ -166,7 +169,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { splitPane.setDividerLocation(0.5); splitPane.setRightComponent(myWrapperPanel); - JScrollPane pane = new JScrollPane(myHierarchyTree); + JScrollPane pane = new JBScrollPane(myHierarchyTree); splitPane.setLeftComponent(pane); add(splitPane, BorderLayout.CENTER); @@ -225,7 +228,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { glassPane.repaint(); } } else { - myHighlightComponent = new HighlightComponent(Color.GREEN); + myHighlightComponent = new HighlightComponent(JBColor.GREEN); final Point pt = SwingUtilities.convertPoint(c, new Point(0, 0), rootPane); myHighlightComponent.setBounds(pt.x, pt.y, c.getWidth(), c.getHeight()); @@ -270,18 +273,20 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { name = component.getClass().getSuperclass().getSimpleName(); } } - + if (!selected) { if (!component.isVisible()) { - foreground = Color.GRAY; - } else if (component.getWidth() == 0 || component.getHeight() == 0) { + foreground = JBColor.GRAY; + } + else if (component.getWidth() == 0 || component.getHeight() == 0) { foreground = new Color(128, 10, 0); - } else if (component.getPreferredSize() != null && - (component.getSize().width < component.getPreferredSize().width - || component.getSize().height < component.getPreferredSize().height)) { + } + else if (component.getPreferredSize() != null && + (component.getSize().width < component.getPreferredSize().width + || component.getSize().height < component.getPreferredSize().height)) { foreground = PlatformColors.BLUE; } - + if (componentNode.getToSelect() == componentNode.getOwnComponent()) { background = new Color(31, 128, 8, 58); } @@ -467,7 +472,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { private DimensionsComponent(@NotNull final Component component) { myComponent = component; setOpaque(true); - setBackground(Color.WHITE); + setBackground(JBColor.WHITE); setBorder(new EmptyBorder(5, 0, 5, 0)); setFont(new JLabel().getFont().deriveFont(Font.PLAIN, 9)); @@ -503,7 +508,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { g2d.drawString(sizeString, bounds.width / 2 - sizeWidth / 2, bounds.height / 2 + fontHeight / 2); - g2d.setColor(Color.GRAY); + g2d.setColor(JBColor.GRAY); int innerX = bounds.width / 2 - sizeWidth / 2 - 20; int innerY = bounds.height / 2 - fontHeight / 2 - 5; @@ -522,10 +527,10 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { } private static void drawInsets(Graphics2D g2d, FontMetrics fm, String name, Insets insets, int offset, int fontHeight, int innerX, int innerY, int innerWidth, int innerHeight) { - g2d.setColor(Color.BLACK); + g2d.setColor(JBColor.BLACK); g2d.drawString(name, innerX - offset + 5, innerY - offset + fontHeight); - g2d.setColor(Color.GRAY); + g2d.setColor(JBColor.GRAY); int dashWidth = fm.stringWidth("-"); if (insets != null) { @@ -558,7 +563,7 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { } private static class ValueCellRenderer implements TableCellRenderer { - private static final Map RENDERERS = new HashMap(); + private static final Map RENDERERS = ContainerUtil.newHashMap(); static { RENDERERS.put(Point.class, new PointRenderer()); @@ -571,45 +576,45 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { RENDERERS.put(Icon.class, new IconRenderer()); } - private static final Renderer DEFAULT_RENDERER = new ObjectRenderer(); + private static final Renderer DEFAULT_RENDERER = new ObjectRenderer(); private static final JLabel NULL_RENDERER = new JLabel("-"); public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (value == null) { - NULL_RENDERER.setOpaque(false); + NULL_RENDERER.setOpaque(isSelected); NULL_RENDERER.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground()); NULL_RENDERER.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground()); return NULL_RENDERER; } - Renderer renderer = getRenderer(value.getClass()); - if (renderer == null) - renderer = DEFAULT_RENDERER; + Renderer renderer = ObjectUtils.notNull(getRenderer(value.getClass()), DEFAULT_RENDERER); JComponent result = renderer.setValue(value); - result.setOpaque(false); + result.setOpaque(isSelected); result.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground()); result.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground()); return result; } @Nullable - private static Renderer getRenderer(Class clazz) { - if (clazz == null) - return null; - Renderer renderer = RENDERERS.get(clazz); - if (renderer != null) - return renderer; + private static Renderer getRenderer(Class clazz) { + if (clazz == null) return null; + + Renderer renderer = (Renderer)RENDERERS.get(clazz); + if (renderer != null) return renderer; + Class[] interfaces = clazz.getInterfaces(); for (Class aClass : interfaces) { renderer = getRenderer(aClass); - if (renderer != null) + if (renderer != null) { return renderer; + } } clazz = clazz.getSuperclass(); - if (clazz != null) + if (clazz != null) { return getRenderer(clazz); + } return null; } } @@ -676,8 +681,11 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { } private static class ObjectRenderer extends JLabel implements Renderer { + { + putClientProperty("html.disable", Boolean.TRUE); + } public JComponent setValue(@NotNull final Object value) { - setText(value.toString()); + setText(String.valueOf(value).replace('\n', ' ')); return this; } } @@ -697,10 +705,15 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { private static class InspectorTableModel extends AbstractTableModel { private static final String[] JCOMPONENT_METHODS = new String[] { - "getLocation", "getLocationOnScreen", "getMinimumSize", "getMaximumSize", "getPreferredSize", "getSize", - "getAlignmentX", "getAlignmentY", "getTooltipText", "getVisibleRect", "getLayout", - "getForeground", "getBackground", "getFont", "isOpaque", "isFocusCycleRoot", "isValid", "isDisplayable", - "isShowing", "isEnabled", "isLightweight", "isFocusable", "isFocusOwner", "getToolTipText", "getText", "isEditable", "getIcon" + "getLocation", "getLocationOnScreen", + "getSize", "isOpaque", "getBorder", + "getForeground", "getBackground", "getFont", + "getMinimumSize", "getMaximumSize", "getPreferredSize", + "getAlignmentX", "getAlignmentY", + "getText", "isEditable", "getIcon", + "getTooltipText", "getToolTipText", + "getVisibleRect", "getLayout", + "isFocusCycleRoot", "isValid", "isDisplayable", "isShowing", "isEnabled", "isLightweight", "isFocusable", "isFocusOwner" }; private Component myComponent; diff --git a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java index 330258dfb510..776c2b9d0ead 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java @@ -283,7 +283,7 @@ public class DumbServiceImpl extends DumbService { } @Override - public void showDumbModeNotification(final String message) { + public void showDumbModeNotification(@NotNull final String message) { UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { @@ -341,14 +341,9 @@ public class DumbServiceImpl extends DumbService { private class IndexUpdateRunnable implements Runnable { private final CacheUpdateRunner myAction; - private double myProcessedItems; - private volatile int myTotalItems; - private double myCurrentBaseTotal; public IndexUpdateRunnable(@NotNull CacheUpdateRunner action) { myAction = action; - myTotalItems = 0; - myCurrentBaseTotal = 0; } @Override @@ -389,12 +384,7 @@ public class DumbServiceImpl extends DumbService { }); } - final ProgressIndicator proxy = new DelegatingProgressIndicator(indicator) { - @Override - public void setFraction(double fraction) { - super.setFraction((myProcessedItems + fraction * myCurrentBaseTotal) / myTotalItems); - } - }; + final ProgressIndicator proxy = new DelegatingProgressIndicator(indicator); final ShutDownTracker shutdownTracker = ShutDownTracker.getInstance(); final Thread self = Thread.currentThread(); @@ -421,16 +411,12 @@ public class DumbServiceImpl extends DumbService { indicator.setText(IdeBundle.message("progress.indexing.scanning")); int count = updateRunner.queryNeededFiles(indicator); - myCurrentBaseTotal = count; - myTotalItems += count; - indicator.setIndeterminate(false); indicator.setText(IdeBundle.message("progress.indexing.updating")); if (count > 0) { updateRunner.processFiles(indicator, true); } updateRunner.updatingDone(); - myProcessedItems += count; } catch (ProcessCanceledException ignored) { } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java index ff4781b26182..75d815313e7e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java @@ -152,9 +152,7 @@ public class JarFileSystemImpl extends JarFileSystem implements ApplicationCompo @Override public JarFile getJarFile(@NotNull VirtualFile entryVFile) throws IOException { - JarHandler handler = getHandler(entryVFile); - - return handler.getJar(); + return getHandler(entryVFile).getJar(); } @Nullable diff --git a/platform/platform-impl/src/com/intellij/ui/Splash.java b/platform/platform-impl/src/com/intellij/ui/Splash.java index 16cfa3ea377c..0f4147f61753 100644 --- a/platform/platform-impl/src/com/intellij/ui/Splash.java +++ b/platform/platform-impl/src/com/intellij/ui/Splash.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * 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. @@ -160,9 +160,9 @@ public class Splash extends JDialog implements StartupProgress { g.setColor(textColor); final String licensedToMessage = provider.getLicensedToMessage(); final List licenseRestrictionsMessages = provider.getLicenseRestrictionsMessages(); - g.drawString(licensedToMessage, x + 21, y + height - 49); + g.drawString(licensedToMessage, x + 15, y + height - 30); if (licenseRestrictionsMessages.size() > 0) { - g.drawString(licenseRestrictionsMessages.get(0), x + 21, y + height - 33); + g.drawString(licenseRestrictionsMessages.get(0), x + 15, y + height - 14); } } return true; diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 6aa37bbc8d9e..dda05b924e0c 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -275,11 +275,6 @@ dump.threads.on.empty.lookup.description=Whether IDEA should issue a thread dump file.structure.tree.mode=true -directory.index.use.root.index=true -directory.index.use.root.index.description=Requires restart -directory.index.compare.implementations=false -directory.index.compare.implementations.description=Will make the IDE slow. Requires restart - disable.toolwindow.overlay=true # suppress inspection "UnusedProperty" disable.toolwindow.overlay.description=Disable transparent toolwindow stripes. @@ -382,4 +377,4 @@ editor.injected.highlighting.enabled.description=Disables injected fragments hig run.processes.with.pty=false -ide.certificate.manager=true \ No newline at end of file +ide.certificate.manager=true diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndex.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndex.java index ef797e7dbe81..24e78d882370 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndex.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndex.java @@ -49,5 +49,9 @@ public abstract class DirectoryIndex { @Nullable public abstract String getPackageName(@NotNull VirtualFile dir); + /** + * @return true + */ + @Deprecated public abstract boolean isInitialized(); } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java index 6e49ebead473..990d0411f0cb 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java @@ -22,8 +22,6 @@ import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.RootPolicy; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ArrayFactory; -import com.intellij.util.ArrayUtil; import com.intellij.util.BitUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -192,7 +190,7 @@ public class DirectoryInfo { } @Override - public int compareTo(OrderEntry o) { + public int compareTo(@NotNull OrderEntry o) { throw new IncorrectOperationException(); } @@ -203,55 +201,6 @@ public class DirectoryInfo { }; } - // orderEntries must be sorted BY_OWNER_MODULE - OrderEntry[] calcNewOrderEntries(@NotNull OrderEntry[] orderEntries, @Nullable DirectoryInfo parentInfo, @Nullable OrderEntry[] oldParentEntries) { - OrderEntry[] newOrderEntries; - if (orderEntries.length == 0) { - newOrderEntries = null; - } - else if (this.orderEntries == null) { - newOrderEntries = orderEntries; - } - else if (parentInfo != null && oldParentEntries == this.orderEntries) { - newOrderEntries = parentInfo.orderEntries; - } - else { - newOrderEntries = mergeWith(orderEntries); - } - return newOrderEntries; - } - - // entries must be sorted BY_OWNER_MODULE - @NotNull - private OrderEntry[] mergeWith(@NotNull OrderEntry[] entries) { - OrderEntry[] orderEntries = this.orderEntries; - OrderEntry[] result = new OrderEntry[orderEntries.length + entries.length]; - int i=0; - int j=0; - // remove equals entries in the process - int o = 0; - while (i != orderEntries.length || j != entries.length) { - OrderEntry m = i != orderEntries.length && (j == entries.length || BY_OWNER_MODULE.compare(orderEntries[i], entries[j]) < 0) - ? orderEntries[i++] - : entries[j++]; - if (o==0 || !m.equals(result[o - 1])) { - result[o++] = m; - } - } - if (o != result.length) { - result = ArrayUtil.realloc(result, o, ORDER_ENTRY_ARRAY_FACTORY); - } - return result; - } - - private static final ArrayFactory ORDER_ENTRY_ARRAY_FACTORY = new ArrayFactory() { - @NotNull - @Override - public OrderEntry[] create(int count) { - return count == 0 ? OrderEntry.EMPTY_ARRAY : new OrderEntry[count]; - } - }; - public static final Comparator BY_OWNER_MODULE = new Comparator() { @Override public int compare(OrderEntry o1, OrderEntry o2) { @@ -291,27 +240,6 @@ public class DirectoryInfo { return module; } - private static T iff(T value, T defaultValue) { - return value == null ? defaultValue : value; - } - - @NotNull - public DirectoryInfo with(Module module, - VirtualFile contentRoot, - VirtualFile sourceRoot, - VirtualFile libraryClassRoot, - int sourceRootTypeData, - OrderEntry[] orderEntries) { - return new DirectoryInfo(iff(module, this.module), iff(contentRoot, this.contentRoot), iff(sourceRoot, this.sourceRoot), - iff(libraryClassRoot, this.libraryClassRoot), sourceRootTypeData == 0 ? this.sourceRootTypeData : (byte)sourceRootTypeData, - iff(orderEntries, this.orderEntries)); - } - - @NotNull - public DirectoryInfo withInternedEntries(@NotNull OrderEntry[] orderEntries) { - return new DirectoryInfo(module, contentRoot, sourceRoot, libraryClassRoot, sourceRootTypeData, orderEntries); - } - @TestOnly void assertConsistency() { OrderEntry[] entries = getOrderEntries(); diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index 163e5e8fea04..373e084192fd 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -560,8 +560,6 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da if (manager instanceof FileDocumentManagerImpl) { ((FileDocumentManagerImpl)manager).dropAllUnsavedDocuments(); } - - ((DirectoryIndexImpl)DirectoryIndex.getInstance(project)).assertAncestorConsistent(); } }.execute().throwException(); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java index 92e56f86e354..117534532d3f 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java @@ -17,6 +17,7 @@ package com.intellij.testFramework.fixtures; import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.codeInsight.daemon.GutterMark; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.lookup.Lookup; @@ -32,7 +33,6 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.codeInsight.daemon.GutterMark; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.vfs.VirtualFile; @@ -53,11 +53,9 @@ import java.util.Collection; import java.util.List; /** - * - * @see IdeaTestFixtureFactory#createCodeInsightFixture(IdeaProjectTestFixture) - * @link http://confluence.jetbrains.net/display/IDEADEV/Testing+IntelliJ+IDEA+Plugins - * * @author Dmitry Avdeev + * @link http://confluence.jetbrains.net/display/IDEADEV/Testing+IntelliJ+IDEA+Plugins + * @see IdeaTestFixtureFactory#createCodeInsightFixture(IdeaProjectTestFixture) */ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { @@ -104,7 +102,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * Copies a file from the testdata directory to the specified path in the test project directory. * * @param sourceFilePath path to the source file, relative to the testdata path. - * @param targetPath path to the destination, relative to the source root of the test project. + * @param targetPath path to the destination, relative to the source root of the test project. * @return the VirtualFile for the copied file in the test project directory. */ VirtualFile copyFileToProject(@TestDataFile @NonNls String sourceFilePath, @NonNls String targetPath); @@ -113,7 +111,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * Copies a directory from the testdata directory to the specified path in the test project directory. * * @param sourceFilePath path to the source directory, relative to the testdata path. - * @param targetPath path to the destination, relative to the source root of the test project. + * @param targetPath path to the destination, relative to the source root of the test project. * @return the VirtualFile for the copied directory in the test project directory. */ VirtualFile copyDirectoryToProject(@NonNls String sourceFilePath, @NonNls String targetPath); @@ -148,7 +146,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * editor. * * @param fileType the file type according to which which the text is interpreted. - * @param text the text to load into the in-memory editor. + * @param text the text to load into the in-memory editor. * @return the PSI file created from the specified text. */ PsiFile configureByText(FileType fileType, @NonNls String text); @@ -158,7 +156,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * editor. * * @param fileName the name of the file (which is used to determine the file type based on the registered filename patterns). - * @param text the text to load into the in-memory editor. + * @param text the text to load into the in-memory editor. * @return the PSI file created from the specified text. */ PsiFile configureByText(String fileName, @NonNls String text); @@ -182,8 +180,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * Creates a file with the specified path and contents in the test project directory. * * @param relativePath the path for the file to create, relative to the test project source root. - * @param fileText the text to put into the created file. - * + * @param fileText the text to put into the created file. * @return the PSI file for the created file. */ PsiFile addFileToProject(@NonNls String relativePath, @NonNls String fileText); @@ -199,7 +196,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { /** * Compares the contents of the in-memory editor with the specified file, optionally ignoring trailing whitespaces. * - * @param expectedFile path to file to check against, relative to the testdata path. + * @param expectedFile path to file to check against, relative to the testdata path. * @param ignoreTrailingWhitespaces whether trailing whitespaces should be ignored by the comparison. */ void checkResultByFile(@TestDataFile @NonNls String expectedFile, boolean ignoreTrailingWhitespaces); @@ -207,11 +204,13 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { /** * Compares a file in the test project with a file in the testdata directory. * - * @param filePath path to file to be checked, relative to the source root of the test project. - * @param expectedFile path to file to check against, relative to the testdata path. + * @param filePath path to file to be checked, relative to the source root of the test project. + * @param expectedFile path to file to check against, relative to the testdata path. * @param ignoreTrailingWhitespaces whether trailing whitespaces should be ignored by the comparison. */ - void checkResultByFile(@NonNls String filePath, @TestDataFile @NonNls String expectedFile, boolean ignoreTrailingWhitespaces); + void checkResultByFile(@TestDataFile @NonNls String filePath, + @TestDataFile @NonNls String expectedFile, + boolean ignoreTrailingWhitespaces); /** * Enables inspections for highlighting tests. @@ -240,21 +239,27 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * Runs highlighting test for the given files. * Checks for {@link #ERROR_MARKER} markers by default. * - * @param checkWarnings enables {@link #WARNING_MARKER} support. - * @param checkInfos enables {@link #INFO_MARKER} support. + * @param checkWarnings enables {@link #WARNING_MARKER} support. + * @param checkInfos enables {@link #INFO_MARKER} support. * @param checkWeakWarnings enables {@link #INFORMATION_MARKER} support. - * @param filePaths the first file is tested only; the others are just copied along the first. - * + * @param filePaths the first file is tested only; the others are just copied along the first. * @return highlighting duration in milliseconds. */ long testHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings, @TestDataFile @NonNls String... filePaths); - long testHighlightingAllFiles(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings, @TestDataFile @NonNls String... filePaths); + long testHighlightingAllFiles(boolean checkWarnings, + boolean checkInfos, + boolean checkWeakWarnings, + @TestDataFile @NonNls String... filePaths); - long testHighlightingAllFiles(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings, @TestDataFile @NonNls VirtualFile... files); + long testHighlightingAllFiles(boolean checkWarnings, + boolean checkInfos, + boolean checkWeakWarnings, + @TestDataFile @NonNls VirtualFile... files); /** * Check highlighting of file already loaded by configure* methods + * * @return duration */ long checkHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings); @@ -266,12 +271,12 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * The same as {@link #testHighlighting(boolean, boolean, boolean, String...)} with all options set. * * @param filePaths the first file is tested only; the others are just copied along with the first. - * * @return highlighting duration in milliseconds */ long testHighlighting(@TestDataFile @NonNls String... filePaths); long testHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings, VirtualFile file); + HighlightTestInfo testFile(@NonNls @NotNull String... filePath); void testInspection(@NotNull String testDir, @NotNull InspectionToolWrapper toolWrapper); @@ -289,7 +294,6 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * Finds the reference in position marked by {@link #CARET_MARKER}. * * @return null if no reference found. - * * @see #getReferenceAtCaretPositionWithAssertion(String...) */ @Nullable @@ -300,7 +304,6 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * Asserts that the reference exists. * * @return founded reference - * * @see #getReferenceAtCaretPosition(String...) */ @NotNull @@ -314,10 +317,10 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * @see #CARET_MARKER */ @NotNull - List getAvailableIntentions(@NonNls String... filePaths); + List getAvailableIntentions(@NonNls @TestDataFile String... filePaths); @NotNull - List getAllQuickFixes(@NonNls String... filePaths); + List getAllQuickFixes(@NonNls @TestDataFile String... filePaths); @NotNull List getAvailableIntentions(); @@ -344,11 +347,11 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * in the in-memory editor and returns an intention action or quickfix with the name exactly matching the specified text. * * @param intentionName the text that the intention text should be equal to. - * @param filePaths the list of file path to copy to the test project directory. + * @param filePaths the list of file path to copy to the test project directory. * @return the first found intention or quickfix, or null if no matching intention actions are found. */ @Nullable - IntentionAction getAvailableIntention(final String intentionName, final String... filePaths); + IntentionAction getAvailableIntention(final String intentionName, @TestDataFile final String... filePaths); /** * Launches the given action. Use {@link #checkResultByFile(String)} to check the result. @@ -367,11 +370,15 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { */ void testCompletion(@TestDataFile @NonNls String fileBefore, @TestDataFile @NonNls String fileAfter, final String... additionalFiles); - void testCompletionTyping(@TestDataFile @NonNls String fileBefore, String toType, @TestDataFile @NonNls String fileAfter, final String... additionalFiles); + void testCompletionTyping(@TestDataFile @NonNls String fileBefore, + String toType, + @TestDataFile @NonNls String fileAfter, + final String... additionalFiles); /** * Runs basic completion in caret position in fileBefore. * Checks that lookup is shown and it contains items with given lookup strings + * * @param items most probably will contain > 1 items */ void testCompletionVariants(@TestDataFile @NonNls String fileBefore, @NonNls String... items); @@ -380,22 +387,22 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * Launches renaming refactoring and checks the result. * * @param fileBefore original file path. Use {@link #CARET_MARKER} to mark the element to rename. - * @param fileAfter result file to be checked against. - * @param newName new name for the element. + * @param fileAfter result file to be checked against. + * @param newName new name for the element. * @see #testRename(String, String) */ void testRename(@TestDataFile @NonNls String fileBefore, @TestDataFile @NonNls String fileAfter, @NonNls String newName, final String... additionalFiles); - void testRename(String fileAfter, String newName); + void testRename(@TestDataFile String fileAfter, String newName); Collection testFindUsages(@TestDataFile @NonNls String... fileNames); Collection findUsages(final PsiElement to); - RangeHighlighter[] testHighlightUsages(String... files); + RangeHighlighter[] testHighlightUsages(@TestDataFile String... files); - void moveFile(@NonNls String filePath, @NonNls String to, final String... additionalFiles); + void moveFile(@NonNls @TestDataFile String filePath, @NonNls String to, final String... additionalFiles); /** * Returns gutter renderer at the caret position. @@ -431,7 +438,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { Document getDocument(PsiFile file); @NotNull - Collection findAllGutters(String filePath); + Collection findAllGutters(@TestDataFile String filePath); void type(final char c); @@ -441,13 +448,14 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { /** * If the action is visible and enabled, perform it + * * @param action * @return updated action's presentation */ Presentation testAction(AnAction action); @Nullable - List getCompletionVariants(String... filesBefore); + List getCompletionVariants(@TestDataFile String... filesBefore); /** * @return null if the only item was auto-completed @@ -476,13 +484,14 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { void allowTreeAccessForAllFiles(); void renameElement(PsiElement element, - String newName, - boolean searchInComments, - boolean searchTextOccurrences); + String newName, + boolean searchInComments, + boolean searchTextOccurrences); T findElementByText(String text, Class elementClass); void testFolding(String fileName); + void testFoldingWithCollapseStatus(String fileName); void assertPreferredCompletionItems(int selected, @NonNls String... expected); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java index 87a0745dbe3e..f53e5080df8a 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java @@ -115,7 +115,6 @@ class HeavyIdeaTestFixtureImpl extends BaseFixture implements HeavyIdeaTestFixtu for (ModuleFixtureBuilder moduleFixtureBuilder : myModuleFixtureBuilders) { moduleFixtureBuilder.getFixture().tearDown(); } - ((DirectoryIndexImpl)DirectoryIndex.getInstance(getProject())).assertAncestorConsistent(); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java index 97bd36698640..fd99994ab9c5 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java @@ -22,8 +22,6 @@ import com.intellij.idea.IdeaTestApplication; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.impl.DirectoryIndex; -import com.intellij.openapi.roots.impl.DirectoryIndexImpl; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; import com.intellij.psi.codeStyle.CodeStyleSchemes; import com.intellij.psi.codeStyle.CodeStyleSettings; @@ -72,7 +70,6 @@ public class LightIdeaTestFixtureImpl extends BaseFixture implements LightIdeaTe super.tearDown(); InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project); PersistentFS.getInstance().clearIdCache(); - ((DirectoryIndexImpl)DirectoryIndex.getInstance(project)).assertAncestorConsistent(); damage.throwIfNotEmpty(); } diff --git a/platform/util/src/com/intellij/icons/AllIcons.java b/platform/util/src/com/intellij/icons/AllIcons.java index b11ef0de0acb..d797aee1999f 100644 --- a/platform/util/src/com/intellij/icons/AllIcons.java +++ b/platform/util/src/com/intellij/icons/AllIcons.java @@ -167,6 +167,7 @@ public class AllIcons { public static final Icon Import = IconLoader.getIcon("/css/import.png"); // 16x16 public static final Icon Property = IconLoader.getIcon("/css/property.png"); // 16x16 public static final Icon Pseudo_element = IconLoader.getIcon("/css/pseudo-element.png"); // 16x16 + public static final Icon Toolwindow = IconLoader.getIcon("/css/toolwindow.png"); // 13x13 } diff --git a/platform/util/src/com/intellij/util/ConcurrencyUtil.java b/platform/util/src/com/intellij/util/ConcurrencyUtil.java index c1eabc757a62..5d04f764636b 100644 --- a/platform/util/src/com/intellij/util/ConcurrencyUtil.java +++ b/platform/util/src/com/intellij/util/ConcurrencyUtil.java @@ -88,51 +88,51 @@ public class ConcurrencyUtil { } @NotNull - public static ThreadPoolExecutor newSingleThreadExecutor(@NotNull @NonNls final String threadFactoryName) { - return newSingleThreadExecutor(threadFactoryName, Thread.NORM_PRIORITY); + public static ThreadPoolExecutor newSingleThreadExecutor(@NotNull @NonNls String name) { + return newSingleThreadExecutor(name, Thread.NORM_PRIORITY); } @NotNull - public static ThreadPoolExecutor newSingleThreadExecutor(@NonNls @NotNull final String threadFactoryName, final int threadPriority) { - return new ThreadPoolExecutor(1, 1, - 0L, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue(), newNamedThreadFactory(threadFactoryName, true, threadPriority)); + public static ThreadPoolExecutor newSingleThreadExecutor(@NonNls @NotNull String name, int priority) { + return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(), newNamedThreadFactory(name, true, priority)); } @NotNull - public static ScheduledThreadPoolExecutor newSingleScheduledThreadExecutor(@NotNull @NonNls final String threadFactoryName) { - return newSingleScheduledThreadExecutor(threadFactoryName, Thread.NORM_PRIORITY); + public static ScheduledThreadPoolExecutor newSingleScheduledThreadExecutor(@NotNull @NonNls String name) { + return newSingleScheduledThreadExecutor(name, Thread.NORM_PRIORITY); } @NotNull - public static ScheduledThreadPoolExecutor newSingleScheduledThreadExecutor(@NonNls @NotNull final String threadFactoryName, final int threadPriority) { - ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, newNamedThreadFactory(threadFactoryName, true, threadPriority)); + public static ScheduledThreadPoolExecutor newSingleScheduledThreadExecutor(@NonNls @NotNull String name, int priority) { + ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, newNamedThreadFactory(name, true, priority)); executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); return executor; } @NotNull - public static ThreadFactory newNamedThreadFactory(@NonNls @NotNull final String threadName, final boolean isDaemon, final int threadPriority) { + public static ThreadFactory newNamedThreadFactory(@NonNls @NotNull final String name, final boolean isDaemon, final int priority) { return new ThreadFactory() { - @NotNull - @Override - public Thread newThread(@NotNull final Runnable r) { - final Thread thread = new Thread(r, threadName); - thread.setDaemon(isDaemon); - thread.setPriority(threadPriority); - return thread; - } - }; + @NotNull + @Override + public Thread newThread(@NotNull Runnable r) { + Thread thread = new Thread(r, name); + thread.setDaemon(isDaemon); + thread.setPriority(priority); + return thread; + } + }; } + @NotNull - public static ThreadFactory newNamedThreadFactory(@NonNls @NotNull final String threadName) { + public static ThreadFactory newNamedThreadFactory(@NonNls @NotNull final String name) { return new ThreadFactory() { - @NotNull - @Override - public Thread newThread(@NotNull final Runnable r) { - return new Thread(r, threadName); - } - }; + @NotNull + @Override + public Thread newThread(@NotNull final Runnable r) { + return new Thread(r, name); + } + }; } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InterfaceMayBeAnnotatedFunctionalInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InterfaceMayBeAnnotatedFunctionalInspection.java index 7c0c2a377803..e4f77e0fbea9 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InterfaceMayBeAnnotatedFunctionalInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InterfaceMayBeAnnotatedFunctionalInspection.java @@ -17,10 +17,7 @@ package com.siyeh.ig.classlayout; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.intention.AddAnnotationPsiFix; -import com.intellij.psi.LambdaHighlightingUtil; -import com.intellij.psi.LambdaUtil; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiNameValuePair; +import com.intellij.psi.*; import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.PsiUtil; import com.siyeh.InspectionGadgetsBundle; @@ -55,7 +52,7 @@ public class InterfaceMayBeAnnotatedFunctionalInspection extends BaseInspection @Override protected InspectionGadgetsFix buildFix(Object... infos) { final PsiClass aClass = (PsiClass)infos[0]; - return new DelegatingFix(new AddAnnotationPsiFix(LambdaUtil.JAVA_LANG_FUNCTIONAL_INTERFACE, aClass, PsiNameValuePair.EMPTY_ARRAY)); + return new DelegatingFix(new AddAnnotationPsiFix(CommonClassNames.JAVA_LANG_FUNCTIONAL_INTERFACE, aClass, PsiNameValuePair.EMPTY_ARRAY)); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InheritanceUtil.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InheritanceUtil.java index 78576339cc31..9661ba10e4c4 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InheritanceUtil.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InheritanceUtil.java @@ -23,8 +23,10 @@ import com.intellij.psi.PsiTypeParameter; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.util.Processor; import com.intellij.util.Query; +import org.jetbrains.annotations.NotNull; import java.util.concurrent.atomic.AtomicInteger; @@ -75,8 +77,9 @@ public class InheritanceUtil { return result[0]; } - public static boolean hasImplementation(PsiClass aClass) { + public static boolean hasImplementation(@NotNull PsiClass aClass) { final SearchScope scope = GlobalSearchScope.projectScope(aClass.getProject()); + if (aClass.isInterface() && FunctionalExpressionSearch.search(aClass, scope).findFirst() != null) return true; final Query search = ClassInheritorsSearch.search(aClass, scope, true, true); return !search.forEach(new Processor() { @Override diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/interface_never_implemented/InterfaceNeverImplemented.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/interface_never_implemented/InterfaceNeverImplemented.java index 259a599e16c3..dc2cb71916bf 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/interface_never_implemented/InterfaceNeverImplemented.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/interface_never_implemented/InterfaceNeverImplemented.java @@ -5,4 +5,14 @@ interface InterfaceWithOnlyOneDirectInheritor {} class Inheritor implements InterfaceWithOnlyOneDirectInheritor {} interface InterfaceWithTwoInheritors {} class Inheritor1 implements InterfaceWithTwoInheritors {} -class Inheritor2 implements InterfaceWithTwoInheritors {} \ No newline at end of file +class Inheritor2 implements InterfaceWithTwoInheritors {} + +interface SAM { + void foo(); +} + +class LambdaCall { + { + SAM sam = () -> {}; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/InterfaceNeverImplementedInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/InterfaceNeverImplementedInspectionTest.java index 4453a28be228..d0bbbac1b820 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/InterfaceNeverImplementedInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/InterfaceNeverImplementedInspectionTest.java @@ -1,10 +1,29 @@ package com.siyeh.ig.inheritance; +import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.testFramework.IdeaTestUtil; import com.siyeh.ig.IGInspectionTestCase; public class InterfaceNeverImplementedInspectionTest extends IGInspectionTestCase { public void test() throws Exception { - doTest("com/siyeh/igtest/inheritance/interface_never_implemented", new InterfaceNeverImplementedInspection()); + final LanguageLevelProjectExtension levelProjectExtension = LanguageLevelProjectExtension.getInstance(getProject()); + final LanguageLevel level = levelProjectExtension.getLanguageLevel(); + try { + levelProjectExtension.setLanguageLevel(LanguageLevel.JDK_1_8); + doTest("com/siyeh/igtest/inheritance/interface_never_implemented", + new LocalInspectionToolWrapper(new InterfaceNeverImplementedInspection()), "java 1.8"); + } + finally { + levelProjectExtension.setLanguageLevel(level); + } + } + + @Override + protected Sdk getTestProjectSdk() { + return IdeaTestUtil.getMockJdk18(); } } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassIntention.java index 317fcfda4c80..a806e9ba0e47 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassIntention.java @@ -16,12 +16,16 @@ package com.siyeh.ipp.interfacetoclass; import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.presentation.java.ClassPresentationUtil; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.ui.ConflictsDialog; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.RefactoringUIUtil; @@ -123,10 +127,20 @@ public class ConvertInterfaceToClassIntention extends Intention { return true; } }); + + final PsiFunctionalExpression functionalExpression = FunctionalExpressionSearch.search(anInterface, searchScope).findFirst(); + if (functionalExpression != null) { + final String conflictMessage = ClassPresentationUtil.getFunctionalExpressionPresentation(functionalExpression, true) + + " will not compile after converting " + RefactoringUIUtil.getDescription(anInterface, false) + " to a class"; + conflicts.putValue(functionalExpression, conflictMessage); + } final boolean conflictsDialogOK; if (conflicts.isEmpty()) { conflictsDialogOK = true; } else { + if (ApplicationManager.getApplication().isUnitTestMode()) { + throw new BaseRefactoringProcessor.ConflictsInTestsException(conflicts.values()); + } final ConflictsDialog conflictsDialog = new ConflictsDialog(anInterface.getProject(), conflicts, new Runnable() { @Override public void run() { diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassPredicate.java index cc9611da1d8c..1fde2428df01 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassPredicate.java @@ -15,6 +15,8 @@ */ package com.siyeh.ipp.interfacetoclass; +import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.psi.CommonClassNames; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.search.SearchScope; @@ -45,6 +47,6 @@ class ConvertInterfaceToClassPredicate implements PsiElementPredicate { return false; } } - return true; + return !AnnotationUtil.isAnnotated(aClass, CommonClassNames.JAVA_LANG_FUNCTIONAL_INTERFACE, true, true); } } diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/interfaceToClass/FunctionalExpressions.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/interfaceToClass/FunctionalExpressions.java new file mode 100644 index 000000000000..b91fd01e2dcc --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/interfaceToClass/FunctionalExpressions.java @@ -0,0 +1,9 @@ +interface FunctionalExpressions { + void foo(); +} + +class Test { + { + FunctionalExpressions fe = () -> {}; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/interfaceToClass/FunctionalInterface.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/interfaceToClass/FunctionalInterface.java new file mode 100644 index 000000000000..ab03809901f8 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/interfaceToClass/FunctionalInterface.java @@ -0,0 +1,4 @@ +@FunctionalInterface +interface FunctionalExpressions { + void foo(); +} diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassTest.java index 9cf5102bf55c..c74f136872cb 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassTest.java @@ -15,6 +15,7 @@ */ package com.siyeh.ipp.interfacetoclass; +import com.intellij.refactoring.BaseRefactoringProcessor; import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ipp.IPPTestCase; @@ -23,6 +24,19 @@ public class ConvertInterfaceToClassTest extends IPPTestCase { public void testExtensionMethods() { doTest(); } public void testInnerInterface() { doTest(); } public void testStaticMethods() { doTest(); } + public void testFunctionalExpressions() { + try { + doTest(); + fail("Conflict not detected"); + } + catch (BaseRefactoringProcessor.ConflictsInTestsException e) { + assertEquals("Functional expression in Test will not compile after converting class FunctionalExpressions to a class", e.getMessage()); + } + } + + public void testFunctionalInterface() throws Exception { + assertIntentionNotAvailable(); + } @Override protected String getRelativePath() { diff --git a/plugins/groovy/testdata/intentions/staticImport/OnDemand2_after.groovy b/plugins/groovy/testdata/intentions/staticImport/OnDemand2_after.groovy index 9de863d41fd9..139e971042a4 100644 --- a/plugins/groovy/testdata/intentions/staticImport/OnDemand2_after.groovy +++ b/plugins/groovy/testdata/intentions/staticImport/OnDemand2_after.groovy @@ -1,4 +1,4 @@ -import static Util.* +import static Util.doSomething class Util { static doSomething(){} @@ -10,4 +10,4 @@ def doSomethingElse(a){} doSomething() doSomething(2) -Util.doSomethingElse(2) \ No newline at end of file +doSomethingElse(2) \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/anonymousFromMap.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/anonymousFromMap.java index 1cb3b2258ab6..d656375ed55f 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/anonymousFromMap.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/anonymousFromMap.java @@ -1,5 +1,5 @@ print(new java.lang.Runnable() { -public void run(java.lang.Object it) {print("foo}");} +public void run(java.lang.Object it) {org.codehaus.groovy.runtime.DefaultGroovyMethods.print(anonymousFromMap.this, "foo}");} public void run() { this.run(null); } diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/closure.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/closure.java index 769c8bd97d8a..e8a4f4a5501c 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/closure.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/closure.java @@ -1,7 +1,7 @@ java.util.ArrayList list = new java.util.ArrayList(java.util.Arrays.asList(1, 2, 3)); org.codehaus.groovy.runtime.DefaultGroovyMethods.each(list, new groovy.lang.Closure(this, this) { public void doCall(java.lang.Integer it) { -print(it); +org.codehaus.groovy.runtime.DefaultGroovyMethods.print(closure.this, it); } public void doCall() { diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/methodParamInClosureImplicitReturn.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/methodParamInClosureImplicitReturn.java index e51530135bbc..99e09df718d2 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/methodParamInClosureImplicitReturn.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/methodParamInClosureImplicitReturn.java @@ -13,7 +13,7 @@ public void foo(int x) {final groovy.lang.Reference i = new g org.codehaus.groovy.runtime.DefaultGroovyMethods.each(new java.util.ArrayList(java.util.Arrays.asList(1, 2, 3)), new groovy.lang.Closure(this, this) { public java.lang.Integer doCall(java.lang.Integer it) { -print(i.get()); +org.codehaus.groovy.runtime.DefaultGroovyMethods.print(methodParamInClosureImplicitReturn.this, i.get()); return setGroovyRef(i, i.get() + 1); } @@ -25,7 +25,7 @@ return doCall(null); org.codehaus.groovy.runtime.DefaultGroovyMethods.each(new java.util.ArrayList(java.util.Arrays.asList(1, 2, 3)), new groovy.lang.Closure(this, this) { public java.lang.Integer doCall(java.lang.Integer it) { -print(i.get()); +org.codehaus.groovy.runtime.DefaultGroovyMethods.print(methodParamInClosureImplicitReturn.this, i.get()); i.set(i.get()++); return i.get(); } diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInScript.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInScript.java index 3956feec017b..346abf3e3546 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInScript.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInScript.java @@ -12,7 +12,7 @@ foo.set(foo.get()++); foo.set(foo.get() + 2); foo.set(foo.get() - 1); foo.set(4); -print(foo.get()); +org.codehaus.groovy.runtime.DefaultGroovyMethods.print(refInClosureInScript.this, foo.get()); } public void doCall() { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcher.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcher.java index 5a9b7b48bb05..8435f6f327d3 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcher.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenJUnitPatcher.java @@ -25,7 +25,9 @@ import org.jetbrains.idea.maven.dom.MavenDomUtil; import org.jetbrains.idea.maven.dom.MavenPropertyResolver; import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel; import org.jetbrains.idea.maven.project.MavenProject; +import org.jetbrains.idea.maven.project.MavenProjectSettings; import org.jetbrains.idea.maven.project.MavenProjectsManager; +import org.jetbrains.idea.maven.project.MavenTestRunningSettings; import org.jetbrains.idea.maven.utils.MavenJDOMUtil; import java.util.List; @@ -45,6 +47,8 @@ public class MavenJUnitPatcher extends JUnitPatcher { Element config = mavenProject.getPluginConfiguration("org.apache.maven.plugins", "maven-surefire-plugin"); if (config == null) return; + MavenTestRunningSettings testRunningSettings = MavenProjectSettings.getInstance(module.getProject()).getTestRunningSettings(); + List paths = MavenJDOMUtil.findChildrenValuesByPath(config, "additionalClasspathElements", "additionalClasspathElement"); if (paths.size() > 0) { @@ -59,39 +63,45 @@ public class MavenJUnitPatcher extends JUnitPatcher { } } - Element systemPropertyVariables = config.getChild("systemPropertyVariables"); - if (systemPropertyVariables != null && isEnabled("systemPropertyVariables")) { - for (Element element : systemPropertyVariables.getChildren()) { - String propertyName = element.getName(); + if (testRunningSettings.isPassEnvironmentVariables() && isEnabled("systemPropertyVariables")) { + Element systemPropertyVariables = config.getChild("systemPropertyVariables"); + if (systemPropertyVariables != null) { + for (Element element : systemPropertyVariables.getChildren()) { + String propertyName = element.getName(); - if (!javaParameters.getVMParametersList().hasProperty(propertyName)) { - String value = resolveSurefireProperties(element.getValue()); - if (isResolved(value)) { - javaParameters.getVMParametersList().addProperty(propertyName, value); + if (!javaParameters.getVMParametersList().hasProperty(propertyName)) { + String value = resolveSurefireProperties(element.getValue()); + if (isResolved(value)) { + javaParameters.getVMParametersList().addProperty(propertyName, value); + } } } } } - Element environmentVariables = config.getChild("environmentVariables"); - if (environmentVariables != null && isEnabled("environmentVariables")) { - for (Element element : environmentVariables.getChildren()) { - String variableName = element.getName(); + if (testRunningSettings.isPassEnvironmentVariables() && isEnabled("environmentVariables")) { + Element environmentVariables = config.getChild("environmentVariables"); + if (environmentVariables != null) { + for (Element element : environmentVariables.getChildren()) { + String variableName = element.getName(); - if (javaParameters.getEnv() == null || !javaParameters.getEnv().containsKey(variableName)) { - String value = resolveSurefireProperties(element.getValue()); - if (isResolved(value)) { - javaParameters.addEnv(variableName, value); + if (javaParameters.getEnv() == null || !javaParameters.getEnv().containsKey(variableName)) { + String value = resolveSurefireProperties(element.getValue()); + if (isResolved(value)) { + javaParameters.addEnv(variableName, value); + } } } } } - Element argLine = config.getChild("argLine"); - if (argLine != null && isEnabled("argLine")) { - String value = resolveSurefireProperties(argLine.getTextTrim()); - if (StringUtil.isNotEmpty(value) && isResolved(value)) { - javaParameters.getVMParametersList().addParametersString(value); + if (testRunningSettings.isPassArgLine() && isEnabled("argLine")) { + Element argLine = config.getChild("argLine"); + if (argLine != null) { + String value = resolveSurefireProperties(argLine.getTextTrim()); + if (StringUtil.isNotEmpty(value) && isResolved(value)) { + javaParameters.getVMParametersList().addParametersString(value); + } } } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectSettings.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectSettings.java new file mode 100644 index 000000000000..4671a261b590 --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectSettings.java @@ -0,0 +1,66 @@ +/* + * 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 org.jetbrains.idea.maven.project; + +import com.intellij.openapi.components.*; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Sergey Evdokimov + */ +@State( + name = "MavenProjectSettings", + storages = {@Storage( + file = StoragePathMacros.PROJECT_CONFIG_DIR + "/mavenProjectSettings.xml")}) +public class MavenProjectSettings implements PersistentStateComponent { + + private final Project myProject; + + private MavenTestRunningSettings myTestRunningSettings = new MavenTestRunningSettings(); + + public MavenProjectSettings() { + this(null); + } + + public MavenProjectSettings(Project project) { + myProject = project; + } + + public static MavenProjectSettings getInstance(@NotNull Project project) { + return ServiceManager.getService(project, MavenProjectSettings.class); + } + + @Nullable + @Override + public MavenProjectSettings getState() { + return this; + } + + public MavenTestRunningSettings getTestRunningSettings() { + return myTestRunningSettings; + } + + public void setTestRunningSettings(MavenTestRunningSettings testRunningSettings) { + myTestRunningSettings = testRunningSettings; + } + + @Override + public void loadState(MavenProjectSettings state) { + this.myTestRunningSettings = state.myTestRunningSettings; + } +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenTestRunningConfigurable.form b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenTestRunningConfigurable.form new file mode 100644 index 000000000000..2b7ae93f3282 --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenTestRunningConfigurable.form @@ -0,0 +1,50 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenTestRunningConfigurable.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenTestRunningConfigurable.java new file mode 100644 index 000000000000..c682ed98d5ed --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenTestRunningConfigurable.java @@ -0,0 +1,111 @@ +/* + * 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 org.jetbrains.idea.maven.project; + +import com.intellij.openapi.options.BaseConfigurable; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SearchableConfigurable; +import com.intellij.openapi.project.Project; +import com.intellij.ui.components.JBCheckBox; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author Sergey Evdokimov + */ +public class MavenTestRunningConfigurable extends BaseConfigurable implements SearchableConfigurable, Configurable.NoScroll { + + private JPanel myMainPanel; + + private JBCheckBox myPassArgLineCB; + private JBCheckBox myPassSystemPropertiesCB; + private JBCheckBox myPassEnvironmentVariablesCB; + + private final Project myProject; + + public MavenTestRunningConfigurable(Project project) { + myProject = project; + } + + @Nls + @Override + public String getDisplayName() { + return ProjectBundle.message("maven.testRunning"); + } + + @Nullable + @Override + public String getHelpTopic() { + return "reference.settings.project.maven.testRunning"; + } + + private void getSettingsFromUI(MavenTestRunningSettings settings) { + settings.setPassArgLine(myPassArgLineCB.isSelected()); + settings.setPassSystemProperties(myPassSystemPropertiesCB.isSelected()); + settings.setPassEnvironmentVariables(myPassEnvironmentVariablesCB.isSelected()); + } + + @Override + public void apply() throws ConfigurationException { + getSettingsFromUI(MavenProjectSettings.getInstance(myProject).getTestRunningSettings()); + } + + @Override + public void reset() { + MavenTestRunningSettings settings = MavenProjectSettings.getInstance(myProject).getTestRunningSettings(); + + myPassArgLineCB.setSelected(settings.isPassArgLine()); + myPassSystemPropertiesCB.setSelected(settings.isPassSystemProperties()); + myPassEnvironmentVariablesCB.setSelected(settings.isPassEnvironmentVariables()); + } + + @Nullable + @Override + public JComponent createComponent() { + return myMainPanel; + } + + @Override + public boolean isModified() { + MavenTestRunningSettings uiSettings = new MavenTestRunningSettings(); + getSettingsFromUI(uiSettings); + + MavenTestRunningSettings projectSettings = MavenProjectSettings.getInstance(myProject).getTestRunningSettings(); + + return !projectSettings.equals(uiSettings); + } + + @Override + public void disposeUIResources() { + + } + + @NotNull + @Override + public String getId() { + return "reference.settings.project.maven.testRunning"; + } + + @Nullable + @Override + public Runnable enableSearch(String option) { + return null; + } +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenTestRunningSettings.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenTestRunningSettings.java new file mode 100644 index 000000000000..04435fa0aaaf --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenTestRunningSettings.java @@ -0,0 +1,72 @@ +/* + * 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 org.jetbrains.idea.maven.project; + +/** + * @author Sergey Evdokimov + */ +public class MavenTestRunningSettings { + + private boolean myPassArgLine; + private boolean myPassEnvironmentVariables; + private boolean myPassSystemProperties; + + public boolean isPassArgLine() { + return myPassArgLine; + } + + public void setPassArgLine(boolean passArgLine) { + myPassArgLine = passArgLine; + } + + public boolean isPassEnvironmentVariables() { + return myPassEnvironmentVariables; + } + + public void setPassEnvironmentVariables(boolean passEnvironmentVariables) { + myPassEnvironmentVariables = passEnvironmentVariables; + } + + public boolean isPassSystemProperties() { + return myPassSystemProperties; + } + + public void setPassSystemProperties(boolean passSystemProperties) { + myPassSystemProperties = passSystemProperties; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MavenTestRunningSettings)) return false; + + MavenTestRunningSettings settings = (MavenTestRunningSettings)o; + + if (myPassArgLine != settings.myPassArgLine) return false; + if (myPassEnvironmentVariables != settings.myPassEnvironmentVariables) return false; + if (myPassSystemProperties != settings.myPassSystemProperties) return false; + + return true; + } + + @Override + public int hashCode() { + int result = (myPassArgLine ? 1 : 0); + result = 31 * result + (myPassEnvironmentVariables ? 1 : 0); + result = 31 * result + (myPassSystemProperties ? 1 : 0); + return result; + } +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenSettings.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenSettings.java index effabc56e4d0..608a31a04c21 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenSettings.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenSettings.java @@ -53,6 +53,8 @@ public class MavenSettings implements SearchableConfigurable.Parent { myChildren.add(new MyMavenRunnerConfigurable(project)); + myChildren.add(new MavenTestRunningConfigurable(project)); + if (!myProject.isDefault()) { myChildren.add(new MavenRepositoriesConfigurable(myProject)); } diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index c1d210a8278a..608de2a8d966 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -51,6 +51,9 @@ id="reference.settings.project.maven.ignored.files" key="maven.tab.ignored.files" bundle="ProjectBundle"/> + @@ -170,7 +173,7 @@ - + diff --git a/plugins/maven/src/main/resources/ProjectBundle.properties b/plugins/maven/src/main/resources/ProjectBundle.properties index 5a1a80c2ab3d..926720c4d82e 100644 --- a/plugins/maven/src/main/resources/ProjectBundle.properties +++ b/plugins/maven/src/main/resources/ProjectBundle.properties @@ -59,6 +59,7 @@ maven.download.ondemand=On demand maven.download.always=On import maven.tab.ignored.files=Ignored Files +maven.testRunning=Running Tests maven.ignore=Ignore Projects maven.unignore=Unignore Projects maven.ingored.no.file=No Maven files diff --git a/xml/dom-openapi/src/com/intellij/patterns/DomFilePattern.java b/xml/dom-openapi/src/com/intellij/patterns/DomFilePattern.java new file mode 100644 index 000000000000..63d59bd43028 --- /dev/null +++ b/xml/dom-openapi/src/com/intellij/patterns/DomFilePattern.java @@ -0,0 +1,42 @@ +/* + * 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.patterns; + +import com.intellij.psi.xml.XmlFile; +import com.intellij.util.ProcessingContext; +import com.intellij.util.xml.DomElement; +import com.intellij.util.xml.DomManager; +import org.jetbrains.annotations.Nullable; + +/** + * @author Dmitry Avdeev + */ +public class DomFilePattern> extends XmlFilePattern { + public DomFilePattern(final Class aClass) { + super(new InitialPatternCondition(XmlFile.class) { + @Override + public boolean accepts(@Nullable Object o, ProcessingContext context) { + return o instanceof XmlFile && DomManager.getDomManager(((XmlFile)o).getProject()).getFileElement((XmlFile)o, aClass) != null; + } + }); + } + + public static class Capture extends DomFilePattern { + public Capture(Class aClass) { + super(aClass); + } + } +} diff --git a/xml/dom-openapi/src/com/intellij/patterns/DomPatterns.java b/xml/dom-openapi/src/com/intellij/patterns/DomPatterns.java index a5f2b3f8c1a1..025b42c5326c 100644 --- a/xml/dom-openapi/src/com/intellij/patterns/DomPatterns.java +++ b/xml/dom-openapi/src/com/intellij/patterns/DomPatterns.java @@ -62,6 +62,10 @@ public class DomPatterns { }); } + public static DomFilePattern.Capture inDomFile(Class rootElementClass) { + return new DomFilePattern.Capture(rootElementClass); + } + public static XmlTagPattern.Capture tagWithDom(String tagName, Class aClass) { return tagWithDom(tagName, domElement(aClass)); }