diff options
author | Tor Norbye <tnorbye@google.com> | 2014-09-04 13:24:04 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2014-09-04 13:24:04 -0700 |
commit | c3d3a90f6b4ead083d63e28e6b9fcea93d675678 (patch) | |
tree | fc0dcd722b6d445468dbe7dad13b4c11781b1cbe /plugins | |
parent | 1aa2e09bdbd413eacb677e9fa4b50630530d0656 (diff) | |
download | idea-c3d3a90f6b4ead083d63e28e6b9fcea93d675678.tar.gz |
Snapshot idea/138.1980 from git://git.jetbrains.org/idea/community.git
Change-Id: Ib567c9c152d770212a7a3db20fbf591c210920bd
Diffstat (limited to 'plugins')
220 files changed, 3843 insertions, 1462 deletions
diff --git a/plugins/ByteCodeViewer/src/com/intellij/byteCodeViewer/ShowByteCodeAction.java b/plugins/ByteCodeViewer/src/com/intellij/byteCodeViewer/ShowByteCodeAction.java index 39d01579b342..1a8bfb7a3558 100644 --- a/plugins/ByteCodeViewer/src/com/intellij/byteCodeViewer/ShowByteCodeAction.java +++ b/plugins/ByteCodeViewer/src/com/intellij/byteCodeViewer/ShowByteCodeAction.java @@ -41,7 +41,6 @@ import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.awt.RelativePoint; -import com.intellij.ui.popup.NotLookupOrSearchCondition; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -138,7 +137,6 @@ public class ShowByteCodeAction extends AnAction { }; final JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(component, null) - .setRequestFocusCondition(project, NotLookupOrSearchCondition.INSTANCE) .setProject(project) .setDimensionServiceKey(project, DocumentationManager.JAVADOC_LOCATION_AND_SIZE, false) .setResizable(true) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml index c8854d4dbb26..81cc13aea292 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml @@ -202,6 +202,10 @@ key="equals.between.inconvertible.types.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.probable.bugs" enabledByDefault="true" level="WARNING" implementationClass="com.siyeh.ig.bugs.EqualsBetweenInconvertibleTypesInspection"/> + <localInspection language="JAVA" shortName="EqualsWithItself" bundle="com.siyeh.InspectionGadgetsBundle" + key="equals.with.itself.display.name" groupBundle="messages.InspectionsBundle" + groupKey="group.names.probable.bugs" enabledByDefault="true" level="WARNING" + implementationClass="com.siyeh.ig.bugs.EqualsWithItselfInspection"/> <localInspection language="JAVA" suppressId="NonFinalFieldReferenceInEquals" shortName="EqualsUsesNonFinalVariable" bundle="com.siyeh.InspectionGadgetsBundle" key="non.final.field.in.equals.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.probable.bugs" enabledByDefault="false" level="WARNING" @@ -1379,6 +1383,14 @@ key="junit3.style.test.method.in.junit4.class.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.junit.JUnit3StyleTestMethodInJUnit4ClassInspection"/> + <localInspection language="JAVA" shortName="JUnit3MethodNamingConvention" + bundle="com.siyeh.InspectionGadgetsBundle" key="junit3.method.naming.convention.display.name" + groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="false" + level="WARNING" implementationClass="com.siyeh.ig.junit.JUnit3MethodNamingConventionInspection"/> + <localInspection language="JAVA" shortName="JUnit4MethodNamingConvention" + bundle="com.siyeh.InspectionGadgetsBundle" key="junit4.method.naming.convention.display.name" + groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="false" + level="WARNING" implementationClass="com.siyeh.ig.junit.JUnit4MethodNamingConventionInspection"/> <localInspection language="JAVA" shortName="JUnit4AnnotatedMethodInJUnit3TestCase" bundle="com.siyeh.InspectionGadgetsBundle" key="junit4.test.method.in.class.extending.junit3.testcase.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="true" level="WARNING" diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index 1dfdfb9eb50a..1df72421fd4d 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1741,6 +1741,7 @@ ignore.test.method.in.class.extending.junit3.testcase.problem.descriptor=JUnit 3 ignore.test.method.in.class.extending.junit3.testcase.quickfix=Remove ''@Ignore'' and rename method to ''{0}'' convert.junit3.test.class.quickfix=Convert JUnit 3 class ''{0}'' to JUnit 4 remove.junit4.test.annotation.quickfix=Remove '@Test' annotation +remove.junit4.test.annotation.and.rename.quickfix=Remove '@Test' annotation and rename to ''{0}'' equals.called.on.enum.constant.display.name='equals()' called on Enum value equals.called.on.enum.constant.problem.descriptor=<code>#ref()</code> called on Enum value #loc equals.called.on.enum.constant.quickfix=Replace 'equals()' with '==' @@ -2100,3 +2101,13 @@ assignment.to.lambda.parameter.problem.descriptor=Assignment to lambda parameter class.with.only.private.constructors.display.name=Class with only 'private' constructors should be declared 'final' class.with.only.private.constructors.problem.descriptor=Class <code>#ref</code> with only 'private' constructors should be declared 'final' property.value.set.to.itself.display.name=Property value set to itself +equals.with.itself.display.name='equals()' called on itself +equals.with.itself.problem.descriptor=Identical qualifier and argument to <code>#ref()</code> call +junit4.method.naming.convention.display.name=JUnit 4 test method naming convention +junit4.method.naming.convention.problem.descriptor.short=JUnit 4 test method name <code>#ref</code> is too short ({0} < {1}) #loc +junit4.method.naming.convention.problem.descriptor.long=JUnit 4 test method name <code>#ref</code> is too long ({0} > {1}) #loc +junit4.method.naming.convention.problem.descriptor.regex.mismatch=JUnit 4 test method name <code>#ref</code> doesn''t match regex ''{0}'' #loc +junit3.method.naming.convention.display.name=JUnit 3 test method naming convention +junit3.method.naming.convention.problem.descriptor.short=JUnit 3 test method name <code>#ref</code> is too short ({0} < {1}) #loc +junit3.method.naming.convention.problem.descriptor.long=JUnit 3 test method name <code>#ref</code> is too long ({0} > {1}) #loc +junit3.method.naming.convention.problem.descriptor.regex.mismatch=JUnit 3 test method name <code>#ref</code> doesn''t match regex ''{0}'' #loc diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/TypeMayBeWeakenedInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/TypeMayBeWeakenedInspection.java index bf23939f2c86..2787f34e4dcf 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/TypeMayBeWeakenedInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/TypeMayBeWeakenedInspection.java @@ -21,7 +21,6 @@ import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.util.Query; import com.siyeh.InspectionGadgetsBundle; @@ -64,9 +63,9 @@ public class TypeMayBeWeakenedInspection extends BaseInspection { @NonNls final StringBuilder builder = new StringBuilder(); final Iterator<PsiClass> iterator = weakerClasses.iterator(); if (iterator.hasNext()) { - builder.append('\'').append(iterator.next().getQualifiedName()).append('\''); + builder.append('\'').append(getClassName(iterator.next())).append('\''); while (iterator.hasNext()) { - builder.append(", '").append(iterator.next().getQualifiedName()).append('\''); + builder.append(", '").append(getClassName(iterator.next())).append('\''); } } final Object info = infos[0]; @@ -85,6 +84,14 @@ public class TypeMayBeWeakenedInspection extends BaseInspection { return InspectionGadgetsBundle.message("type.may.be.weakened.problem.descriptor", builder.toString()); } + private static String getClassName(PsiClass aClass) { + final String qualifiedName = aClass.getQualifiedName(); + if (qualifiedName == null) { + return aClass.getName(); + } + return qualifiedName; + } + @Override @Nullable public JComponent createOptionsPanel() { @@ -106,11 +113,11 @@ public class TypeMayBeWeakenedInspection extends BaseInspection { final Iterable<PsiClass> weakerClasses = (Iterable<PsiClass>)infos[1]; final Collection<InspectionGadgetsFix> fixes = new ArrayList(); for (PsiClass weakestClass : weakerClasses) { - final String qualifiedName = weakestClass.getQualifiedName(); - if (qualifiedName == null) { + final String className = getClassName(weakestClass); + if (className == null) { continue; } - fixes.add(new TypeMayBeWeakenedFix(qualifiedName)); + fixes.add(new TypeMayBeWeakenedFix(className)); } return fixes.toArray(new InspectionGadgetsFix[fixes.size()]); } @@ -162,31 +169,30 @@ public class TypeMayBeWeakenedInspection extends BaseInspection { if (!(oldType instanceof PsiClassType)) { return; } - final PsiClassType classType = (PsiClassType)oldType; - final PsiType[] parameterTypes = classType.getParameters(); - final GlobalSearchScope scope = element.getResolveScope(); + final PsiClassType oldClassType = (PsiClassType)oldType; + final PsiType[] parameterTypes = oldClassType.getParameters(); final JavaPsiFacade facade = JavaPsiFacade.getInstance(project); - final PsiClass aClass = facade.findClass(fqClassName, scope); - if (aClass == null) { + final PsiElementFactory factory = facade.getElementFactory(); + final PsiType type = factory.createTypeFromText(fqClassName, element); + if (!(type instanceof PsiClassType)) { return; } - final PsiTypeParameter[] typeParameters = aClass.getTypeParameters(); - final PsiElementFactory factory = facade.getElementFactory(); - final PsiClassType type; - if (typeParameters.length != 0 && typeParameters.length == parameterTypes.length) { - final Map<PsiTypeParameter, PsiType> typeParameterMap = new HashMap(); - for (int i = 0; i < typeParameters.length; i++) { - final PsiTypeParameter typeParameter = typeParameters[i]; - final PsiType parameterType = parameterTypes[i]; - typeParameterMap.put(typeParameter, parameterType); + PsiClassType classType = (PsiClassType)type; + final PsiClass aClass = classType.resolve(); + if (aClass != null) { + final PsiTypeParameter[] typeParameters = aClass.getTypeParameters(); + if (typeParameters.length != 0 && typeParameters.length == parameterTypes.length) { + final Map<PsiTypeParameter, PsiType> typeParameterMap = new HashMap(); + for (int i = 0; i < typeParameters.length; i++) { + final PsiTypeParameter typeParameter = typeParameters[i]; + final PsiType parameterType = parameterTypes[i]; + typeParameterMap.put(typeParameter, parameterType); + } + final PsiSubstitutor substitutor = factory.createSubstitutor(typeParameterMap); + classType = factory.createType(aClass, substitutor); } - final PsiSubstitutor substitutor = factory.createSubstitutor(typeParameterMap); - type = factory.createType(aClass, substitutor); - } - else { - type = factory.createTypeByFQClassName(fqClassName, scope); } - final PsiJavaCodeReferenceElement referenceElement = factory.createReferenceElementByType(type); + final PsiJavaCodeReferenceElement referenceElement = factory.createReferenceElementByType(classType); final PsiElement replacement = componentReferenceElement.replace(referenceElement); final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(project); javaCodeStyleManager.shortenClassReferences(replacement); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/EqualsWithItselfInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/EqualsWithItselfInspection.java new file mode 100644 index 000000000000..698ace189a6b --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/EqualsWithItselfInspection.java @@ -0,0 +1,78 @@ +/* + * 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.siyeh.ig.bugs; + +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiExpressionList; +import com.intellij.psi.PsiMethodCallExpression; +import com.intellij.psi.PsiReferenceExpression; +import com.siyeh.InspectionGadgetsBundle;import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.EquivalenceChecker; +import com.siyeh.ig.psiutils.MethodCallUtils; +import com.siyeh.ig.psiutils.SideEffectChecker; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Bas Leijdekkers + */ +public class EqualsWithItselfInspection extends BaseInspection { + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("equals.with.itself.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("equals.with.itself.problem.descriptor"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new EqualsWithIfSelfVisitor(); + } + + private static class EqualsWithIfSelfVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (!MethodCallUtils.isEqualsCall(expression)) { + return; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + final PsiExpression[] arguments = argumentList.getExpressions(); + if (arguments.length != 1) { + return; + } + final PsiExpression argument = arguments[0]; + if (!EquivalenceChecker.expressionsAreEquivalent(qualifier, argument) || + SideEffectChecker.mayHaveSideEffects(qualifier)) { + return; + } + registerMethodCallError(expression); + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.java index 1289bbdbe694..c24de84ba1ea 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/inheritance/StaticInheritanceFix.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. @@ -30,6 +30,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.psi.impl.DebugUtil; +import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; @@ -91,7 +92,13 @@ class StaticInheritanceFix extends InspectionGadgetsFix { @Override public void run(@NotNull ProgressIndicator indicator) { for (final PsiField field : allFields) { - final Query<PsiReference> search = ReferencesSearch.search(field, implementingClass.getUseScope(), false); + SearchScope scope = ApplicationManager.getApplication().runReadAction(new Computable<SearchScope>() { + @Override + public SearchScope compute() { + return implementingClass.getUseScope(); + } + }); + final Query<PsiReference> search = ReferencesSearch.search(field, scope, false); for (PsiReference reference : search) { if (!(reference instanceof PsiReferenceExpression)) { continue; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit3MethodNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit3MethodNamingConventionInspectionBase.java new file mode 100644 index 000000000000..8f27342d8d2b --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit3MethodNamingConventionInspectionBase.java @@ -0,0 +1,102 @@ +/* + * 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.siyeh.ig.junit; + +import com.intellij.psi.PsiIdentifier; +import com.intellij.psi.PsiMethod; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.naming.ConventionInspection; +import com.siyeh.ig.psiutils.LibraryUtil; +import com.siyeh.ig.psiutils.MethodUtils; +import com.siyeh.ig.psiutils.TestUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Bas Leijdekkers + */ +public class JUnit3MethodNamingConventionInspectionBase extends ConventionInspection { + + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("junit3.method.naming.convention.display.name"); + } + + @Override + @NotNull + public String buildErrorString(Object... infos) { + final String methodName = (String)infos[0]; + final int length = methodName.length(); + if (length < getMinLength()) { + return InspectionGadgetsBundle.message("junit3.method.naming.convention.problem.descriptor.short", + Integer.valueOf(length), Integer.valueOf(getMinLength())); + } + else if (length > getMaxLength()) { + return InspectionGadgetsBundle.message("junit3.method.naming.convention.problem.descriptor.long", + Integer.valueOf(length), Integer.valueOf(getMaxLength())); + } + return InspectionGadgetsBundle.message("junit3.method.naming.convention.problem.descriptor.regex.mismatch", getRegex()); + } + + @Override + protected String getDefaultRegex() { + return "test[A-Za-z_\\d]*"; + } + + @Override + protected int getDefaultMinLength() { + return 8; + } + + @Override + protected int getDefaultMaxLength() { + return 64; + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new JUnit3MethodNamingConventionVisitor(); + } + + private class JUnit3MethodNamingConventionVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (!TestUtils.isJUnit3TestMethod(method) || !TestUtils.isRunnable(method)) { + return; + } + final PsiIdentifier nameIdentifier = method.getNameIdentifier(); + if (nameIdentifier == null) { + return; + } + final String name = method.getName(); + if (isValid(name)) { + return; + } + if (!isOnTheFly() && MethodUtils.hasSuper(method)) { + return; + } + if (LibraryUtil.isOverrideOfLibraryMethod(method)) { + return; + } + registerMethodError(method, name); + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java index 8a6ebeff68ce..c39865049e95 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 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. @@ -25,6 +25,7 @@ import com.siyeh.ig.DelegatingFix; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.TestUtils; import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -71,70 +72,45 @@ public class JUnit3StyleTestMethodInJUnit4ClassInspection extends BaseInspection if (!name.startsWith("test")) { return; } - if (method.hasModifierProperty(PsiModifier.ABSTRACT) || !method.hasModifierProperty(PsiModifier.PUBLIC)) { + if (!TestUtils.isRunnable(method)) { return; } if (TestUtils.isJUnit4TestMethod(method)) { return; } - final PsiType returnType = method.getReturnType(); - if (returnType == null || !returnType.equals(PsiType.VOID)) { - return; - } - final PsiParameterList parameterList = method.getParameterList(); - if (parameterList.getParametersCount() != 0) { - return; - } final PsiClass containingClass = method.getContainingClass(); if (TestUtils.isJUnitTestClass(containingClass)) { return; } - if (!containsReferenceToClass(containingClass, "org.junit.Test")) { + if (!containsJUnit4Annotation(containingClass)) { return; } registerMethodError(method); } } - public static boolean containsReferenceToClass(PsiElement element, String fullyQualifiedName) { - final ClassReferenceVisitor visitor = new ClassReferenceVisitor(fullyQualifiedName); + public static boolean containsJUnit4Annotation(PsiElement element) { + final JUnit4AnnotationVisitor visitor = new JUnit4AnnotationVisitor(); element.accept(visitor); - return visitor.isReferenceFound(); + return visitor.isJUnit4AnnotationFound(); } - private static class ClassReferenceVisitor extends JavaRecursiveElementVisitor { - - private final String fullyQualifiedName; - private boolean referenceFound = false; + private static class JUnit4AnnotationVisitor extends JavaRecursiveElementWalkingVisitor { - private ClassReferenceVisitor(String fullyQualifiedName) { - this.fullyQualifiedName = fullyQualifiedName; - } + private boolean myJUnit4AnnotationFound = false; @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - super.visitReferenceElement(reference); - if (referenceFound) { - return; - } - if (!(reference.getParent() instanceof PsiAnnotation)) { - // optimization - return; - } - final PsiElement element = reference.resolve(); - if (!(element instanceof PsiClass) || element instanceof PsiTypeParameter) { - return; - } - final PsiClass aClass = (PsiClass)element; - final String classQualifiedName = aClass.getQualifiedName(); - if (classQualifiedName == null || !classQualifiedName.equals(fullyQualifiedName)) { + public void visitAnnotation(PsiAnnotation annotation) { + super.visitAnnotation(annotation); + @NonNls final String qualifiedName = annotation.getQualifiedName(); + if (qualifiedName == null || !qualifiedName.startsWith("org.junit.")) { return; } - referenceFound = true; + myJUnit4AnnotationFound = true; } - public boolean isReferenceFound() { - return referenceFound; + public boolean isJUnit4AnnotationFound() { + return myJUnit4AnnotationFound; } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit4MethodNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit4MethodNamingConventionInspectionBase.java new file mode 100644 index 000000000000..eb0f3d7b91c7 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/JUnit4MethodNamingConventionInspectionBase.java @@ -0,0 +1,102 @@ +/* + * 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.siyeh.ig.junit; + +import com.intellij.psi.PsiIdentifier; +import com.intellij.psi.PsiMethod; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.naming.ConventionInspection; +import com.siyeh.ig.psiutils.LibraryUtil; +import com.siyeh.ig.psiutils.MethodUtils; +import com.siyeh.ig.psiutils.TestUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Bas Leijdekkers + */ +public class JUnit4MethodNamingConventionInspectionBase extends ConventionInspection { + + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("junit4.method.naming.convention.display.name"); + } + + @Override + @NotNull + public String buildErrorString(Object... infos) { + final String methodName = (String)infos[0]; + final int length = methodName.length(); + if (length < getMinLength()) { + return InspectionGadgetsBundle.message("junit4.method.naming.convention.problem.descriptor.short", + Integer.valueOf(length), Integer.valueOf(getMinLength())); + } + else if (length > getMaxLength()) { + return InspectionGadgetsBundle.message("junit4.method.naming.convention.problem.descriptor.long", + Integer.valueOf(length), Integer.valueOf(getMaxLength())); + } + return InspectionGadgetsBundle.message("junit4.method.naming.convention.problem.descriptor.regex.mismatch", getRegex()); + } + + @Override + protected String getDefaultRegex() { + return "[a-z][A-Za-z_\\d]*"; + } + + @Override + protected int getDefaultMinLength() { + return 4; + } + + @Override + protected int getDefaultMaxLength() { + return 64; + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new JUnit4MethodNamingConventionVisitor(); + } + + private class JUnit4MethodNamingConventionVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (!TestUtils.isJUnit4TestMethod(method) || !TestUtils.isRunnable(method)) { + return; + } + final PsiIdentifier nameIdentifier = method.getNameIdentifier(); + if (nameIdentifier == null) { + return; + } + final String name = method.getName(); + if (isValid(name)) { + return; + } + if (!isOnTheFly() && MethodUtils.hasSuper(method)) { + return; + } + if (LibraryUtil.isOverrideOfLibraryMethod(method)) { + return; + } + registerMethodError(method, name); + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspection.java index 02d8cd5b7c8e..4b9a794a143a 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,14 +15,14 @@ */ package com.siyeh.ig.junit; -import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.psi.*; -import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiParameterList; +import com.intellij.psi.PsiType; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.TestUtils; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; public class TestMethodIsPublicVoidNoArgInspection extends BaseInspection { @@ -70,23 +70,20 @@ public class TestMethodIsPublicVoidNoArgInspection extends BaseInspection { @Override public void visitMethod(@NotNull PsiMethod method) { //note: no call to super; - @NonNls final String methodName = method.getName(); - if (!methodName.startsWith("test") && - !TestUtils.isJUnit4TestMethod(method)) { + if (method.isConstructor()) { return; } - final PsiType returnType = method.getReturnType(); - if (returnType == null) { + if (!TestUtils.isJUnit3TestMethod(method) && !TestUtils.isJUnit4TestMethod(method)) { return; } + final PsiType returnType = method.getReturnType(); final PsiParameterList parameterList = method.getParameterList(); final boolean takesArguments; final boolean isStatic; if (parameterList.getParametersCount() == 0) { takesArguments = false; isStatic = method.hasModifierProperty(PsiModifier.STATIC); - if (!isStatic && returnType.equals(PsiType.VOID) && - method.hasModifierProperty(PsiModifier.PUBLIC)) { + if (!isStatic && PsiType.VOID.equals(returnType) && method.hasModifierProperty(PsiModifier.PUBLIC)) { return; } } @@ -94,14 +91,6 @@ public class TestMethodIsPublicVoidNoArgInspection extends BaseInspection { isStatic = false; takesArguments = true; } - final PsiClass targetClass = method.getContainingClass(); - if (!AnnotationUtil.isAnnotated(method, "org.junit.Test", true)) { - if (targetClass == null || - !InheritanceUtil.isInheritor(targetClass, - "junit.framework.TestCase")) { - return; - } - } registerMethodError(method, Boolean.valueOf(takesArguments), Boolean.valueOf(isStatic)); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java index 3ec38f55053c..964ce0b0aace 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionBase.java @@ -15,25 +15,22 @@ */ package com.siyeh.ig.naming; +import com.intellij.openapi.extensions.Extensions; import com.intellij.psi.PsiIdentifier; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; -import com.intellij.util.ui.CheckBox; +import com.intellij.testIntegration.TestFramework; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.LibraryUtil; import com.siyeh.ig.psiutils.MethodUtils; +import com.siyeh.ig.psiutils.TestUtils; import org.jetbrains.annotations.NotNull; -import javax.swing.*; - public class InstanceMethodNamingConventionInspectionBase extends ConventionInspection { private static final int DEFAULT_MIN_LENGTH = 4; private static final int DEFAULT_MAX_LENGTH = 32; - @SuppressWarnings("PublicField") - public boolean ignoreNativeMethods = true; - @Override @NotNull public String getDisplayName() { @@ -59,13 +56,6 @@ public class InstanceMethodNamingConventionInspectionBase extends ConventionInsp } @Override - public JComponent[] createExtraOptions() { - return new JComponent[] { - new CheckBox("ignore 'native' methods", this, "ignoreNativeMethods") - }; - } - - @Override protected String getDefaultRegex() { return "[a-z][A-Za-z\\d]*"; } @@ -80,6 +70,16 @@ public class InstanceMethodNamingConventionInspectionBase extends ConventionInsp return DEFAULT_MAX_LENGTH; } + private static boolean isTestNGTestMethod(PsiMethod method) { + final TestFramework[] testFrameworks = Extensions.getExtensions(TestFramework.EXTENSION_NAME); + for (TestFramework framework : testFrameworks) { + if ("TestNG".equals(framework.getName())) { + return framework.isTestMethod(method); + } + } + return false; + } + @Override public BaseInspectionVisitor buildVisitor() { return new NamingConventionsVisitor(); @@ -93,13 +93,24 @@ public class InstanceMethodNamingConventionInspectionBase extends ConventionInsp if (method.isConstructor() || method.hasModifierProperty(PsiModifier.STATIC)) { return; } - if (ignoreNativeMethods && method.hasModifierProperty(PsiModifier.NATIVE)) { + if (method.hasModifierProperty(PsiModifier.NATIVE) && isInspectionEnabled("NativeMethodNamingConvention", method)) { return; } final PsiIdentifier nameIdentifier = method.getNameIdentifier(); if (nameIdentifier == null) { return; } + if (TestUtils.isRunnable(method)) { + if (TestUtils.isJUnit4TestMethod(method) && isInspectionEnabled("JUnit4MethodNamingConvention", method)) { + return; + } + if (TestUtils.isJUnit3TestMethod(method) && isInspectionEnabled("JUnit3MethodNamingConvention", method)) { + return; + } + } + if (isTestNGTestMethod(method) && isInspectionEnabled("TestNGMethodNamingConvention", method)) { + return; + } final String name = method.getName(); if (isValid(name)) { return; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NativeMethodNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NativeMethodNamingConventionInspectionBase.java index a8ceb11a11b1..2231fa152678 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NativeMethodNamingConventionInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/NativeMethodNamingConventionInspectionBase.java @@ -77,7 +77,7 @@ public class NativeMethodNamingConventionInspectionBase extends ConventionInspec @Override public void visitMethod(@NotNull PsiMethod method) { super.visitMethod(method); - if (method.isConstructor() || method.hasModifierProperty(PsiModifier.STATIC)) { + if (method.isConstructor()) { return; } if (!method.hasModifierProperty(PsiModifier.NATIVE)) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java index 116d2208e452..3e0d08998ec0 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionBase.java @@ -17,20 +17,14 @@ package com.siyeh.ig.naming; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; -import com.intellij.util.ui.CheckBox; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspectionVisitor; import org.jetbrains.annotations.NotNull; -import javax.swing.*; - public class StaticMethodNamingConventionInspectionBase extends ConventionInspection { private static final int DEFAULT_MIN_LENGTH = 4; private static final int DEFAULT_MAX_LENGTH = 32; - @SuppressWarnings("PublicField") - public boolean ignoreNativeMethods = true; - @Override @NotNull public String getDisplayName() { @@ -61,13 +55,6 @@ public class StaticMethodNamingConventionInspectionBase extends ConventionInspec } @Override - public JComponent[] createExtraOptions() { - return new JComponent[]{ - new CheckBox("ignore 'native' methods", this, "ignoreNativeMethods") - }; - } - - @Override protected String getDefaultRegex() { return "[a-z][A-Za-z\\d]*"; } @@ -95,7 +82,7 @@ public class StaticMethodNamingConventionInspectionBase extends ConventionInspec if (!method.hasModifierProperty(PsiModifier.STATIC)) { return; } - if (ignoreNativeMethods && method.hasModifierProperty(PsiModifier.NATIVE)) { + if (method.hasModifierProperty(PsiModifier.NATIVE) && isInspectionEnabled("NativeMethodNamingConvention", method)) { return; } final String name = method.getName(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/PointlessArithmeticExpressionInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/PointlessArithmeticExpressionInspection.java index 023b4bc9f949..2dde6969545d 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/PointlessArithmeticExpressionInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/PointlessArithmeticExpressionInspection.java @@ -29,6 +29,7 @@ import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.PsiReplacementUtil; import com.siyeh.ig.psiutils.EquivalenceChecker; import com.siyeh.ig.psiutils.ExpressionUtils; +import com.siyeh.ig.psiutils.SideEffectChecker; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -232,7 +233,7 @@ public class PointlessArithmeticExpressionInspection for (int i = 0; i < expressions.length; i++) { PsiExpression expression = expressions[i]; if (previousExpression != null && - (isZero(expression) || i == 1 && EquivalenceChecker.expressionsAreEquivalent(previousExpression, expression))) { + (isZero(expression) || areExpressionsIdenticalWithoutSideEffects(previousExpression, expression, i))) { return true; } previousExpression = expression; @@ -260,9 +261,10 @@ public class PointlessArithmeticExpressionInspection private boolean divideExpressionIsPointless(PsiExpression[] expressions) { PsiExpression previousExpression = null; - for (PsiExpression expression : expressions) { + for (int i = 0; i < expressions.length; i++) { + final PsiExpression expression = expressions[i]; if (previousExpression != null && - (isOne(expression) || EquivalenceChecker.expressionsAreEquivalent(previousExpression, expression))) { + (isOne(expression) || areExpressionsIdenticalWithoutSideEffects(previousExpression, expression, i))) { return true; } previousExpression = expression; @@ -272,15 +274,21 @@ public class PointlessArithmeticExpressionInspection private boolean modExpressionIsPointless(PsiExpression[] expressions) { PsiExpression previousExpression = null; - for (PsiExpression expression : expressions) { + for (int i = 0; i < expressions.length; i++) { + final PsiExpression expression = expressions[i]; if (previousExpression != null && - (isOne(expression) || EquivalenceChecker.expressionsAreEquivalent(previousExpression, expression))) { + (isOne(expression) || areExpressionsIdenticalWithoutSideEffects(previousExpression, expression, i))) { return true; } previousExpression = expression; } return false; } + + private boolean areExpressionsIdenticalWithoutSideEffects(PsiExpression expression1, PsiExpression expression2, int index) { + return index == 1 && EquivalenceChecker.expressionsAreEquivalent(expression1, expression2) && + !SideEffectChecker.mayHaveSideEffects(expression1); + } } boolean isZero(PsiExpression expression) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java index 9b4a3a832913..7bfaae8cc722 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java @@ -67,6 +67,9 @@ public class ImportUtils { !hasDefaultImportConflict(qualifiedName, javaFile) && !hasOnDemandImportConflict(qualifiedName, javaFile)) { return; } + if (hasExactImportConflict(qualifiedName, javaFile)) { + return; + } final Project project = importList.getProject(); final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); final PsiElementFactory elementFactory = psiFacade.getElementFactory(); @@ -156,7 +159,7 @@ public class ImportUtils { return false; } - private static boolean hasExactImportConflict(String fqName, PsiJavaFile file) { + public static boolean hasExactImportConflict(String fqName, PsiJavaFile file) { final PsiImportList imports = file.getImportList(); if (imports == null) { return false; 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 9661ba10e4c4..faea625f1db5 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InheritanceUtil.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InheritanceUtil.java @@ -15,6 +15,7 @@ */ package com.siyeh.ig.psiutils; +import com.intellij.codeInspection.inheritance.ImplementedAtRuntimeCondition; import com.intellij.openapi.progress.ProgressManager; import com.intellij.psi.CommonClassNames; import com.intellij.psi.PsiClass; @@ -80,6 +81,11 @@ public class InheritanceUtil { 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; + for (ImplementedAtRuntimeCondition condition : ImplementedAtRuntimeCondition.EP_NAME.getExtensions()) { + if (condition.isImplementedAtRuntime(aClass)) { + return true; + } + } final Query<PsiClass> search = ClassInheritorsSearch.search(aClass, scope, true, true); return !search.forEach(new Processor<PsiClass>() { @Override diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java index 5063ef7c2ea7..782b667469af 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java @@ -17,6 +17,7 @@ package com.siyeh.ig.psiutils; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PropertyUtil; import org.jetbrains.annotations.NotNull; public class SideEffectChecker { @@ -59,6 +60,14 @@ public class SideEffectChecker { return; } super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if ((methodName.startsWith("is") || methodName.startsWith("get")) && expression.getArgumentList().getExpressions().length == 0) { + final PsiMethod method = expression.resolveMethod(); + if (PropertyUtil.isSimpleGetter(method)) { + return; + } + } mayHaveSideEffects = true; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java index cf2133299768..dcaf8390dc5d 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,8 @@ import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.util.*; import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -66,34 +66,37 @@ public class TestUtils { } public static boolean isJUnitTestMethod(@Nullable PsiMethod method) { + return isRunnable(method) && (isJUnit3TestMethod(method) || isJUnit4TestMethod(method)); + } + + public static boolean isRunnable(PsiMethod method) { if (method == null) { return false; } - if (isJUnit4TestMethod(method)) { - return true; - } - final String methodName = method.getName(); - @NonNls final String test = "test"; - if (!methodName.startsWith(test)) { - return false; - } if (method.hasModifierProperty(PsiModifier.ABSTRACT) || + method.hasModifierProperty(PsiModifier.STATIC) || !method.hasModifierProperty(PsiModifier.PUBLIC)) { return false; } final PsiType returnType = method.getReturnType(); - if (returnType == null) { + if (!PsiType.VOID.equals(returnType)) { return false; } - if (!returnType.equals(PsiType.VOID)) { + final PsiParameterList parameterList = method.getParameterList(); + return parameterList.getParametersCount() == 0; + } + + public static boolean isJUnit3TestMethod(@Nullable PsiMethod method) { + if (method == null) { return false; } - final PsiParameterList parameterList = method.getParameterList(); - if (parameterList.getParametersCount() != 0) { + final String methodName = method.getName(); + @NonNls final String test = "test"; + if (!methodName.startsWith(test)) { return false; } - final PsiClass targetClass = method.getContainingClass(); - return isJUnitTestClass(targetClass); + final PsiClass containingClass = method.getContainingClass(); + return isJUnitTestClass(containingClass); } public static boolean isJUnit4TestMethod(@Nullable PsiMethod method) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarilyQualifiedInnerClassAccessInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarilyQualifiedInnerClassAccessInspection.java index 78e32e5eee60..e449ad98fc8f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarilyQualifiedInnerClassAccessInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarilyQualifiedInnerClassAccessInspection.java @@ -99,7 +99,10 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection extends BaseInspec } final PsiClass aClass = (PsiClass)target; ImportUtils.addImportIfNeeded(aClass, element); - element.delete(); + final String shortName = aClass.getName(); + if (isReferenceToTarget(shortName, aClass, parent)) { + element.delete(); + } } } @@ -108,6 +111,20 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection extends BaseInspec return new UnnecessarilyQualifiedInnerClassAccessVisitor(); } + private static boolean isReferenceToTarget(String referenceText, @NotNull PsiClass target, PsiElement context) { + final PsiJavaCodeReferenceElement reference = + JavaPsiFacade.getElementFactory(target.getProject()).createReferenceFromText(referenceText, context); + final JavaResolveResult[] results = reference.multiResolve(false); + if (results.length == 0) { + return true; + } + if (results.length > 1) { + return false; + } + final JavaResolveResult result = results[0]; + return result.isAccessible() && target.equals(result.getElement()); + } + private class UnnecessarilyQualifiedInnerClassAccessVisitor extends BaseInspectionVisitor { @@ -175,20 +192,6 @@ public class UnnecessarilyQualifiedInnerClassAccessInspection extends BaseInspec visitReferenceElement(expression); } - private boolean isReferenceToTarget(String referenceText, @NotNull PsiClass target, PsiElement context) { - final PsiJavaCodeReferenceElement reference = - JavaPsiFacade.getElementFactory(target.getProject()).createReferenceFromText(referenceText, context); - final JavaResolveResult[] results = reference.multiResolve(false); - if (results.length == 0) { - return true; - } - if (results.length > 1) { - return false; - } - final JavaResolveResult result = results[0]; - return result.isAccessible() && target.equals(result.getElement()); - } - private boolean isInImportOrPackage(PsiElement element) { while (element instanceof PsiJavaCodeReferenceElement) { element = element.getParent(); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit3MethodNamingConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit3MethodNamingConventionInspection.java new file mode 100644 index 000000000000..29dcf0bf1a01 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit3MethodNamingConventionInspection.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.junit; + +import com.siyeh.ig.InspectionGadgetsFix; +import com.siyeh.ig.fixes.RenameFix; + +/** + * @author Bas Leijdekkers + */ +public class JUnit3MethodNamingConventionInspection extends JUnit3MethodNamingConventionInspectionBase { + + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + return new RenameFix(); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit4AnnotatedMethodInJUnit3TestCaseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit4AnnotatedMethodInJUnit3TestCaseInspection.java index 252411527cc1..89ad944a0f78 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit4AnnotatedMethodInJUnit3TestCaseInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit4AnnotatedMethodInJUnit3TestCaseInspection.java @@ -18,6 +18,7 @@ package com.siyeh.ig.junit; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.siyeh.InspectionGadgetsBundle; @@ -41,7 +42,16 @@ public class JUnit4AnnotatedMethodInJUnit3TestCaseInspection extends JUnit4Annot fixes.add(new RemoveIgnoreAndRename(method)); } if (TestUtils.isJUnit4TestMethod(method)) { - fixes.add(new RemoveTestAnnotationFix()); + String methodName = method.getName(); + String newMethodName; + if (methodName.startsWith("test")) { + newMethodName = null; + } + else { + boolean lowCaseStyle = methodName.contains("_"); + newMethodName = "test" + (lowCaseStyle ? "_" + methodName : StringUtil.capitalize(methodName)); + } + fixes.add(new RemoveTestAnnotationFix(newMethodName)); } final PsiClass aClass = (PsiClass)infos[0]; final String className = aClass.getName(); @@ -233,22 +243,33 @@ public class JUnit4AnnotatedMethodInJUnit3TestCaseInspection extends JUnit4Annot } } - private static class RemoveTestAnnotationFix extends InspectionGadgetsFix { + private static class RemoveTestAnnotationFix extends RenameFix { + private final String myNewName; + + public RemoveTestAnnotationFix(String newName) { + super(newName); + myNewName = newName; + } + @Override @NotNull public String getFamilyName() { - return getName(); + return InspectionGadgetsBundle.message("remove.junit4.test.annotation.quickfix"); } @Override @NotNull public String getName() { - return InspectionGadgetsBundle.message("remove.junit4.test.annotation.quickfix"); + return myNewName == null ? getFamilyName() + : InspectionGadgetsBundle.message("remove.junit4.test.annotation.and.rename.quickfix", myNewName); } @Override - protected void doFix(Project project, ProblemDescriptor descriptor) { + public void doFix(Project project, ProblemDescriptor descriptor) { deleteAnnotation(descriptor, "org.junit.Test"); + if (myNewName != null) { + super.doFix(project, descriptor); + } } } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit4MethodNamingConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit4MethodNamingConventionInspection.java new file mode 100644 index 000000000000..22c8937d48d9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/JUnit4MethodNamingConventionInspection.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.junit; + +import com.siyeh.ig.InspectionGadgetsFix; +import com.siyeh.ig.fixes.RenameFix; + +/** + * @author Bas Leijdekkers + */ +public class JUnit4MethodNamingConventionInspection extends JUnit4MethodNamingConventionInspectionBase { + + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + return new RenameFix(); + } +} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsWithItself.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsWithItself.html new file mode 100644 index 000000000000..3e1491edd22e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsWithItself.html @@ -0,0 +1,10 @@ +<html> +<body> +Reports call to <b>equals()</b> were an object is compared for equality with itself. +This means that the argument and the qualifier to the call are identical. +In this case <b>equals()</b> will always return <b>true</b>. +<!-- tooltip end --> +<p> +<small>New in 14</small> +</body> +</html>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceMethodNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceMethodNamingConvention.html index a6933cf0c7b8..4bf1c67710c5 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceMethodNamingConvention.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceMethodNamingConvention.html @@ -8,8 +8,6 @@ methods are ignored by this inspection. Use the fields below to specify minimum length, maximum length and regular expression expected for instance method names. Specify <b>0</b> to not check the length of names. Regular expressions are in standard <b>java.util.regex</b> format. <p> -Use the checkbox below to ignore native methods. -<p> </body> </html>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/JUnit3MethodNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/JUnit3MethodNamingConvention.html new file mode 100644 index 000000000000..253c7297cdcc --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/JUnit3MethodNamingConvention.html @@ -0,0 +1,13 @@ +<html> +<body> +Reports JUnit 3 test methods whose names are either too short, too long, or do not follow the specified regular expression pattern. +When this inspection is enabled, the <i>Instance method naming convention</i> inspection +will ignore JUnit 3 test methods automatically. +<!-- tooltip end --> +<p> +Use the fields below to specify minimum length, maximum length and regular expression expected for JUnit 3 test method names. +Specify <b>0</b> to not check the length of names. Regular expressions are in standard <b>java.util.regex</b> format. +<p> +<small>New in 14</small> +</body> +</html>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/JUnit4MethodNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/JUnit4MethodNamingConvention.html new file mode 100644 index 000000000000..a53cc8817015 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/JUnit4MethodNamingConvention.html @@ -0,0 +1,13 @@ +<html> +<body> +Reports JUnit 4 test methods whose names are either too short, too long, or do not follow the specified regular expression pattern. +When this inspection is enabled, the <i>Instance method naming convention</i> inspection +will ignore JUnit 4 test methods automatically. +<!-- tooltip end --> +<p> +Use the fields below to specify minimum length, maximum length and regular expression expected for JUnit 4 test method names. +Specify <b>0</b> to not check the length of names. Regular expressions are in standard <b>java.util.regex</b> format. +<p> +<small>New in 14</small> +</body> +</html>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html index c2e866b3d223..2ffd3a2a27a3 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethodNamingConvention.html @@ -1,11 +1,13 @@ <html> <body> -Reports 'native' methods whose names are either too short, too long, or do not follow +Reports <b>native</b> methods whose names are either too short, too long, or do not follow the specified regular expression pattern. Methods that override library methods are ignored by this inspection. +When this inspection is enabled, the <i>Instance method naming convention</i> and +<i>'static' method naming convention</i> inspections will ignore <b>native</b> methods automatically. <!-- tooltip end --> <p> -Use the fields below to specify minimum length, maximum length and regular expression expected for 'native' method names. +Use the fields below to specify minimum length, maximum length and regular expression expected for <b>native</b> method names. Specify <b>0</b> to not check the length of names. Regular expressions are in standard <b>java.util.regex</b> format. <p> <small>New in 14</small> diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticMethodNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticMethodNamingConvention.html index 37d12a6af08d..c0ced0ba01bd 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticMethodNamingConvention.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticMethodNamingConvention.html @@ -7,8 +7,6 @@ the specified regular expression pattern. Use the fields below to specify minimum length, maximum length and regular expression expected for static method names. Specify <b>0</b> to not check the length of names. Regular expressions are in standard <b>java.util.regex</b> format. <p> -Use the checkbox below to ignore native methods. -<p> </body> </html>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodIsPublicVoidNoArg.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodIsPublicVoidNoArg.html index a31b39a1a710..fe227cae1fbc 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodIsPublicVoidNoArg.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodIsPublicVoidNoArg.html @@ -1,8 +1,8 @@ <html> <body> -Reports any JUnit test methods whose names which are not declared +Reports any JUnit test methods which are declared <b>static</b>, not declared <b>public</b>, do not return -<b>void</b>, or take arguments. +<b>void</b>, or have parameters. Such test methods are easy to create inadvertently, but will not be executed by JUnit test runners. <!-- tooltip end --> diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/abstraction/type_may_be_weakened/LocalClass.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/abstraction/type_may_be_weakened/LocalClass.after.java new file mode 100644 index 000000000000..42653ac7af63 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/abstraction/type_may_be_weakened/LocalClass.after.java @@ -0,0 +1,11 @@ +class LocalClass { + + void foo() { + class A<T> { + void foo() {} + } + class B<T> extends A<T> {} + A<String> bb = new B(); + bb.foo(); + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/abstraction/type_may_be_weakened/LocalClass.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/abstraction/type_may_be_weakened/LocalClass.java new file mode 100644 index 000000000000..1c905035b914 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/abstraction/type_may_be_weakened/LocalClass.java @@ -0,0 +1,11 @@ +class LocalClass { + + void foo() { + class A<T> { + void foo() {} + } + class B<T> extends A<T> {} + B<String> b<caret>b = new B(); + bb.foo(); + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/TypeMayBeWeakened.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/TypeMayBeWeakened.java index 370aba53a19c..a134fcd8d9fb 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/TypeMayBeWeakened.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/TypeMayBeWeakened.java @@ -162,4 +162,15 @@ class Test implements Foo2 { interface Foo { void bar(); } -interface Foo2 extends Foo {}
\ No newline at end of file +interface Foo2 extends Foo {} +class Helper { + + void foo() { + class A<T> { + void foo() {} + } + class B<T> extends A<T> {} + B<String> <warning descr="Type of variable 'b' may be weakened to 'A'">b</warning> = new B(); + b.foo(); + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/equals_with_itself/EqualsWithItself.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/equals_with_itself/EqualsWithItself.java new file mode 100644 index 000000000000..03347da345a5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/equals_with_itself/EqualsWithItself.java @@ -0,0 +1,23 @@ +class EqualsWithItself { + + boolean foo(Object o) { + return o.<warning descr="Identical qualifier and argument to 'equals()' call">equals</warning>(((o))); + } + + boolean withGetter() { + return getValue().<warning descr="Identical qualifier and argument to 'equals()' call">equals</warning>(getValue()); + } + + boolean withMethodCall() { + return build().equals(build()); + } + + private Integer value = 1; + public Integer getValue() { + return value; + } + + public Object build() { + return new Object(); + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithNoTestMethodsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithNoTestMethodsInspection.java deleted file mode 100644 index f2f0afea3a7c..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithNoTestMethodsInspection.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.siyeh.igtest.junit; - -import junit.framework.TestCase; - -public class TestCaseWithNoTestMethodsInspection extends TestCase -{ - public TestCaseWithNoTestMethodsInspection() - { - } - - public void teardown() - { - - } -} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_method_naming_convention/JUnit3MethodNamingConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_method_naming_convention/JUnit3MethodNamingConvention.java new file mode 100644 index 000000000000..fbe2e70e0945 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_method_naming_convention/JUnit3MethodNamingConvention.java @@ -0,0 +1,10 @@ +public class JUnit3MethodNamingConvention extends junit.framework.TestCase { + + public void <warning descr="JUnit 3 test method name 'testA' is too short (5 < 8)">testA</warning>() {} + + public void <warning descr="JUnit 3 test method name 'testAbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz' is too long (82 > 64)">testAbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz</warning>() {} + + public void <warning descr="JUnit 3 test method name 'testGiveMeMore$$$' doesn't match regex 'test[A-Za-z_\d]*'">testGiveMeMore$$$</warning>() {} + + public void test_me_properly() {} +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/BeforeAnnotationUsed.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/BeforeAnnotationUsed.java new file mode 100644 index 000000000000..6ef566f99035 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/BeforeAnnotationUsed.java @@ -0,0 +1,9 @@ +import org.junit.Before; + +public class BeforeAnnotationUsed { + + @Before + public void before() {} + + public void <warning descr="Old style JUnit test method 'testOldStyle()' in JUnit 4 class">testOldStyle</warning>() {} +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/JUnit3StyleTestMethodInJUnit4Class.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/JUnit3StyleTestMethodInJUnit4Class.java new file mode 100644 index 000000000000..e5df9e6d40ba --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit3_style_test_method_in_junit4_class/JUnit3StyleTestMethodInJUnit4Class.java @@ -0,0 +1,10 @@ +import org.junit.Test; + +public class JUnit3StyleTestMethodInJUnit4Class { + + @Test + public void junit4Test() { + } + + public void <warning descr="Old style JUnit test method 'testJUnit3()' in JUnit 4 class">testJUnit3</warning>() {} +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit4_method_naming_convention/JUnit4MethodNamingConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit4_method_naming_convention/JUnit4MethodNamingConvention.java new file mode 100644 index 000000000000..69379a9abb87 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/junit4_method_naming_convention/JUnit4MethodNamingConvention.java @@ -0,0 +1,16 @@ +import org.junit.Test; + +public class JUnit4MethodNamingConvention { + + @Test + public void <warning descr="JUnit 4 test method name 'a' is too short (1 < 4)">a</warning>() {} + + @Test + public void <warning descr="JUnit 4 test method name 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz' is too long (78 > 64)">abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz</warning>() {} + + @Test + public void <warning descr="JUnit 4 test method name 'more$$$' doesn't match regex '[a-z][A-Za-z_\d]*'">more$$$</warning>() {} + + @Test + public void assure_foo_is_never_null() {} +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_case_with_no_test_methods/TestCaseWithNoTestMethods.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_case_with_no_test_methods/TestCaseWithNoTestMethods.java new file mode 100644 index 000000000000..559dcce72720 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_case_with_no_test_methods/TestCaseWithNoTestMethods.java @@ -0,0 +1,19 @@ +public class <warning descr="JUnit test case 'TestCaseWithNoTestMethods' has no tests">TestCaseWithNoTestMethods</warning> extends junit.framework.TestCase { + + TestCaseWithNoTestMethods() {} + + public int testOne() { + return 1; + } + + public static void testTwo() {} + void testThree() {} + public void testFour(int i) {} + + public void setUp() throws Exception { + super.setUp(); + } + public void tearDown() throws Exception { + super.tearDown(); + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit3TestMethodIsPublicVoidNoArg.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit3TestMethodIsPublicVoidNoArg.java new file mode 100644 index 000000000000..68a5df1305f6 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit3TestMethodIsPublicVoidNoArg.java @@ -0,0 +1,16 @@ +public class JUnit3TestMethodIsPublicVoidNoArg extends junit.framework.TestCase { + + public JUnit3TestMethodIsPublicVoidNoArg() {} + + void <warning descr="Test method 'testOne()' is not declared 'public void'">testOne</warning>() {} + + public int <warning descr="Test method 'testTwo()' is not declared 'public void'">testTwo</warning>() { + return 2; + } + + public static void <warning descr="Test method 'testThree()' should not be 'static'">testThree</warning>() {} + + public void <warning descr="Test method 'testFour()' should probably not have parameters">testFour</warning>(int i) {} + + public void testFive() {} +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit4TestMethodIsPublicVoidNoArg.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit4TestMethodIsPublicVoidNoArg.java new file mode 100644 index 000000000000..8641acb3b49e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/test_method_is_public_void_no_arg/JUnit4TestMethodIsPublicVoidNoArg.java @@ -0,0 +1,24 @@ +import org.junit.Test; + +public class JUnit4TestMethodIsPublicVoidNoArg { + + @Test + JUnit4TestMethodIsPublicVoidNoArg() {} + + @Test + void <warning descr="Test method 'testOne()' is not declared 'public void'">testOne</warning>() {} + + @Test + public int <warning descr="Test method 'testTwo()' is not declared 'public void'">testTwo</warning>() { + return 2; + } + + @Test + public static void <warning descr="Test method 'testThree()' should not be 'static'">testThree</warning>() {} + + @Test + public void <warning descr="Test method 'testFour()' should probably not have parameters">testFour</warning>(int i) {} + + @Test + public void testFive() {} +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/if_switch/IfCanBeSwitch.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/if_switch/IfCanBeSwitch.java index 7bfc8aa08ff0..a0456798059d 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/if_switch/IfCanBeSwitch.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/if_switch/IfCanBeSwitch.java @@ -2,15 +2,15 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; class IfCanBeSwitch { void m1(int i) { // ok - if (i == 0) System.out.println("zero"); else if (i == 1) System.out.println("one"); else System.out.println("many"); + <warning descr="'if' statement replaceable with 'switch' statement">if</warning> (i == 0) System.out.println("zero"); else if (i == 1) System.out.println("one"); else System.out.println("many"); } void m1(char c) { // ok - if (c == '0') System.out.println("zero"); else if (c == '1') System.out.println("one"); else System.out.println("many"); + <warning descr="'if' statement replaceable with 'switch' statement">if</warning> (c == '0') System.out.println("zero"); else if (c == '1') System.out.println("one"); else System.out.println("many"); } void m1(byte i) { // ok - if (i == (byte)0) System.out.println("zero"); else if (i == (byte)1) System.out.println("one"); else System.out.println("many"); + <warning descr="'if' statement replaceable with 'switch' statement">if</warning> (i == (byte)0) System.out.println("zero"); else if (i == (byte)1) System.out.println("one"); else System.out.println("many"); } void m2(int i) { // bad, long literals @@ -23,7 +23,7 @@ class IfCanBeSwitch { void polyadic() { String s = null; - if (s.equals("asdf") || s.equals("addd") || s.equals("lkjh")) { + <warning descr="'if' statement replaceable with 'switch' statement">if</warning> (s.equals("asdf") || s.equals("addd") || s.equals("lkjh")) { System.out.println("asdf"); } else if (s.equals("null")) { @@ -59,14 +59,14 @@ class IfCanBeSwitch { } void nullSafe(String earth) { - if (earth.equals("foo")) { + <warning descr="'if' statement replaceable with 'switch' statement">if</warning> (earth.equals("foo")) { } else if ("bar".equals(earth)) { } else { } } void nullSafe2(@NotNull String narf) { - if ("foo".equals((narf))) { + <warning descr="'if' statement replaceable with 'switch' statement">if</warning> ("foo".equals((narf))) { // do this } else if ("bar".equals(narf)){ // do that @@ -75,4 +75,21 @@ class IfCanBeSwitch { // do something else. } } + + Num num; + enum Num { + ONE, TWO + } + Num getNum() { + return num; + } + void ifWithGetterToSwitch() { + <warning descr="'if' statement replaceable with 'switch' statement">if</warning> (getNum() == Num.ONE) { + System.out.println(1); + } else if (getNum() == Num.TWO) { + System.out.println(2); + } else { + System.out.println("-"); + } + } }
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/if_switch/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/if_switch/expected.xml deleted file mode 100644 index e56ebb574747..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/if_switch/expected.xml +++ /dev/null @@ -1,44 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<problems> - <problem> - <file>IfCanBeSwitch.java</file> - <line>5</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'if' replaceable with 'switch'</problem_class> - <description><code>if</code> statement replaceable with 'switch' statement #loc</description> - </problem> - - <problem> - <file>IfCanBeSwitch.java</file> - <line>9</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'if' replaceable with 'switch'</problem_class> - <description><code>if</code> statement replaceable with 'switch' statement #loc</description> - </problem> - - <problem> - <file>IfCanBeSwitch.java</file> - <line>13</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'if' replaceable with 'switch'</problem_class> - <description><code>if</code> statement replaceable with 'switch' statement #loc</description> - </problem> - - <problem> - <file>IfCanBeSwitch.java</file> - <line>26</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'if' replaceable with 'switch'</problem_class> - <description><code>if</code> statement replaceable with 'switch' statement #loc</description> - </problem> - - <problem> - <file>IfCanBeSwitch.java</file> - <line>62</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'if' replaceable with 'switch'</problem_class> - <description><code>if</code> statement replaceable with 'switch' statement #loc</description> - </problem> - - <problem> - <file>IfCanBeSwitch.java</file> - <line>69</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'if' replaceable with 'switch'</problem_class> - <description><code>if</code> statement replaceable with 'switch' statement #loc</description> - </problem> -</problems>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/native_method_naming_convention/NativeMethodNamingConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/native_method_naming_convention/NativeMethodNamingConvention.java index 9f39c4ceb884..9b8a8e66d289 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/native_method_naming_convention/NativeMethodNamingConvention.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/native_method_naming_convention/NativeMethodNamingConvention.java @@ -28,4 +28,6 @@ public class NativeMethodNamingConvention implements Runnable public native void run(); private void a() {} + + public static native void <warning descr="'native' method name 'b' is too short">b</warning>(); } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/pointless_arithmetic_expression/PointlessArithmeticExpression.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/pointless_arithmetic_expression/PointlessArithmeticExpression.java index 4ba7a97033ad..9a10262e3148 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/pointless_arithmetic_expression/PointlessArithmeticExpression.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/pointless_arithmetic_expression/PointlessArithmeticExpression.java @@ -1,5 +1,7 @@ package com.siyeh.igtest.numeric.pointless_arithmetic_expression; +import java.util.Random; + public class PointlessArithmeticExpression { private static final int ZERO_CONSTANT = 0; @@ -8,11 +10,11 @@ public class PointlessArithmeticExpression public static void main(String[] args) { final int i = 2; - final int j = i + 0; + final int j = <warning descr="'i + 0' can be replaced with 'i'">i + 0</warning>; System.out.println(j); - int k = 0+j; + int k = <warning descr="'0+j' can be replaced with 'j'">0+j</warning>; System.out.println(k); - k = j - 0; + k = <warning descr="'j - 0' can be replaced with 'j'">j - 0</warning>; System.out.println(k); k = 0 - j; System.out.println(k); @@ -20,11 +22,11 @@ public class PointlessArithmeticExpression System.out.println(k); k = j * ONE_CONSTANT; System.out.println(k); - k = j / 1; + k = <warning descr="'j / 1' can be replaced with 'j'">j / 1</warning>; System.out.println(k); String string = "foo" + 0; - k = j%1; + k = <warning descr="'j%1' can be replaced with '0'">j%1</warning>; System.out.println(k); if(k<=Integer.MAX_VALUE) @@ -90,9 +92,9 @@ public class PointlessArithmeticExpression } void more(int i) { - System.out.println(i / i); - System.out.println(i - i); - System.out.println(i % i); + System.out.println(<warning descr="'i / i' can be replaced with '1'">i / i</warning>); + System.out.println(<warning descr="'i - i' can be replaced with '0'">i - i</warning>); + System.out.println(<warning descr="'i % i' can be replaced with '0'">i % i</warning>); } } class Main { @@ -111,18 +113,29 @@ class Main { return (CONST + (new Main(5).i) * 8) - (Main.CONST + new Main(5).i * (8)); } - int one = 5/5; + int one = <warning descr="'5/5' can be replaced with '1'">5/5</warning>; } class Expanded {{ - int m = 1/**/ - (byte)0 - 9; // warn - int j = 8 * 0 * 8; - int k = 1 + /*a*/0 +/**/ 9; - byte l = (byte) (1L - 1L); + int m = <warning descr="'1/**/ - (byte)0 - 9' can be replaced with '1/**/ - 9'">1/**/ - (byte)0 - 9</warning>; // warn + int j = <warning descr="'8 * 0 * 8' can be replaced with '0'">8 * 0 * 8</warning>; + int k = <warning descr="'1 + /*a*/0 +/**/ 9' can be replaced with '1 + /*a*//**/ 9'">1 + /*a*/0 +/**/ 9</warning>; + byte l = (byte) (<warning descr="'1L - 1L' can be replaced with '0L'">1L - 1L</warning>); byte u = 1; - int z = 2 / 1 / 1; - System.out.println(u * 1); - long g = 8L / 8L; - long h = 9L * 0L; - int a = 8 * 0 * 8 * ; // don't warn + int z = <warning descr="'2 / 1 / 1' can be replaced with '2 / 1'">2 / 1 / 1</warning>; + System.out.println(<warning descr="'u * 1' can be replaced with 'u'">u * 1</warning>); + long g = <warning descr="'8L / 8L' can be replaced with '1L'">8L / 8L</warning>; + long h = <warning descr="'9L * 0L' can be replaced with '0L'">9L * 0L</warning>; + int a = 8 * 0 * 8 *<error descr="Expression expected"> </error>; // don't warn int minus = 2 - 1 - 1; -}}
\ No newline at end of file + int div = 3 / 2 / 2; + int mod = 3 % 2 % 2; +}} +class SideEffects { + public static void main( String args[] ){ + Random rand = new Random(); + int array[] = {1, 2, 4}; + int i = 1; + int b = array[i++] - array[i++]; + System.out.println(rand.nextInt(1000) - rand.nextInt(1000)); + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/pointless_arithmetic_expression/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/pointless_arithmetic_expression/expected.xml deleted file mode 100644 index f6af12237ea0..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/pointless_arithmetic_expression/expected.xml +++ /dev/null @@ -1,129 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<problems> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>11</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>i + 0</code> can be replaced with 'i' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>13</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>0+j</code> can be replaced with 'j' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>15</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>j - 0</code> can be replaced with 'j' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>23</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>j / 1</code> can be replaced with 'j' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>27</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>j%1</code> can be replaced with '0' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>93</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>i / i</code> can be replaced with '1' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>94</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>i - i</code> can be replaced with '0' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>95</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>i % i</code> can be replaced with '0' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>111</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>(CONST + (new Main(5).i) * 8) - (Main.CONST + new Main(5).i * (8))</code> can be replaced with '0' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>114</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>5/5</code> can be replaced with '1' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>117</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>1/**/ - (byte)0 - 9</code> can be replaced with '1/**/ - 9' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>118</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>8 * 0 * 8</code> can be replaced with '0' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>119</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>1 + /*a*/0 +/**/ 9</code> can be replaced with '1 + /*a*//**/ 9' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>120</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>1L - 1L</code> can be replaced with '0L' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>122</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>2 / 1 / 1</code> can be replaced with '2 / 1' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>123</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>u * 1</code> can be replaced with 'u' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>124</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>8L / 8L</code> can be replaced with '1L' #loc</description> - </problem> - - <problem> - <file>PointlessArithmeticExpression.java</file> - <line>125</line> - <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class> - <description><code>9L * 0L</code> can be replaced with '0L' #loc</description> - </problem> -</problems>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/LightInspectionTestCase.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/LightInspectionTestCase.java index d262e31333ba..951d14ad9f8b 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/LightInspectionTestCase.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/LightInspectionTestCase.java @@ -109,15 +109,20 @@ public abstract class LightInspectionTestCase extends LightCodeInsightFixtureTes lastWord = lastWord.substring(0, lastWord.length() - 10); } final int length = lastWord.length(); + boolean upperCase = false; for (int i = 0; i < length; i++) { final char ch = lastWord.charAt(i); if (Character.isUpperCase(ch)) { - if (i != 0) { - basePath.append('_'); + if (!upperCase) { + upperCase = true; + if (i != 0) { + basePath.append('_'); + } } basePath.append(Character.toLowerCase(ch)); } else { + upperCase = false; basePath.append(ch); } } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/EqualsWithItselfInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/EqualsWithItselfInspectionTest.java new file mode 100644 index 000000000000..868884ffa6db --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/EqualsWithItselfInspectionTest.java @@ -0,0 +1,34 @@ +/* + * 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.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class EqualsWithItselfInspectionTest extends LightInspectionTestCase { + + public void testEqualsWithItself() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new EqualsWithItselfInspection(); + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/abstraction/TypeMayBeWeakenedFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/abstraction/TypeMayBeWeakenedFixTest.java index 58373f3a3955..d4b9ec3039bb 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/abstraction/TypeMayBeWeakenedFixTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/abstraction/TypeMayBeWeakenedFixTest.java @@ -12,10 +12,13 @@ public class TypeMayBeWeakenedFixTest extends IGQuickFixesTestCase { @Override public void setUp() throws Exception { super.setUp(); - myFixture.enableInspections(new TypeMayBeWeakenedInspection()); + final TypeMayBeWeakenedInspection inspection = new TypeMayBeWeakenedInspection(); + inspection.onlyWeakentoInterface = false; + myFixture.enableInspections(inspection); myRelativePath = "abstraction/type_may_be_weakened"; } public void testShorten() { doTest(InspectionGadgetsBundle.message("type.may.be.weakened.quickfix", "java.util.Collection")); } + public void testLocalClass() { doTest(InspectionGadgetsBundle.message("type.may.be.weakened.quickfix", "A")); } } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit3MethodNamingConventionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit3MethodNamingConventionInspectionTest.java new file mode 100644 index 000000000000..d71792bcbbc9 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit3MethodNamingConventionInspectionTest.java @@ -0,0 +1,45 @@ +/* + * 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.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class JUnit3MethodNamingConventionInspectionTest extends LightInspectionTestCase { + + public void testJUnit3MethodNamingConvention() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new JUnit3MethodNamingConventionInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package junit.framework;" + + "public abstract class TestCase {" + + " protected void setUp() throws Exception {}" + + " protected void tearDown() throws Exception {}" + + "}" + }; + } +} diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspectionTest.java new file mode 100644 index 000000000000..eb7e979f81e1 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit3StyleTestMethodInJUnit4ClassInspectionTest.java @@ -0,0 +1,57 @@ +/* + * 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.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class JUnit3StyleTestMethodInJUnit4ClassInspectionTest extends LightInspectionTestCase { + + public void testJUnit3StyleTestMethodInJUnit4Class() { doTest(); } + public void testBeforeAnnotationUsed() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new JUnit3StyleTestMethodInJUnit4ClassInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package org.junit;" + + "import java.lang.annotation.ElementType;" + + "import java.lang.annotation.Retention;" + + "import java.lang.annotation.RetentionPolicy;" + + "import java.lang.annotation.Target;" + + "@Retention(RetentionPolicy.RUNTIME)" + + "@Target({ElementType.METHOD})" + + "public @interface Before {}", + "package org.junit;" + + "import java.lang.annotation.ElementType;" + + "import java.lang.annotation.Retention;" + + "import java.lang.annotation.RetentionPolicy;" + + "import java.lang.annotation.Target;" + + "@Retention(RetentionPolicy.RUNTIME)" + + "@Target({ElementType.METHOD})" + + "public @interface Test {}" + }; + } +} diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit4MethodNamingConventionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit4MethodNamingConventionInspectionTest.java new file mode 100644 index 000000000000..bff20e9bd24a --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/JUnit4MethodNamingConventionInspectionTest.java @@ -0,0 +1,48 @@ +/* + * 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.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class JUnit4MethodNamingConventionInspectionTest extends LightInspectionTestCase { + + public void testJUnit4MethodNamingConvention() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new JUnit4MethodNamingConventionInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package org.junit;" + + "import java.lang.annotation.ElementType;" + + "import java.lang.annotation.Retention;" + + "import java.lang.annotation.RetentionPolicy;" + + "import java.lang.annotation.Target;" + + "@Retention(RetentionPolicy.RUNTIME)" + + "@Target({ElementType.METHOD})" + + "public @interface Test {}" + }; + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestCaseWithNoTestMethodsInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestCaseWithNoTestMethodsInspectionTest.java new file mode 100644 index 000000000000..e8566eacdcd0 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestCaseWithNoTestMethodsInspectionTest.java @@ -0,0 +1,45 @@ +/* + * 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.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class TestCaseWithNoTestMethodsInspectionTest extends LightInspectionTestCase { + + public void testTestCaseWithNoTestMethods() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new TestCaseWithNoTestMethodsInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package junit.framework;" + + "public abstract class TestCase {" + + " protected void setUp() throws Exception {}" + + " protected void tearDown() throws Exception {}" + + "}" + }; + } +} diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspectionTest.java new file mode 100644 index 000000000000..72406191f2b1 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspectionTest.java @@ -0,0 +1,46 @@ +/* + * 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.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class TestMethodIsPublicVoidNoArgInspectionTest extends LightInspectionTestCase { + + public void testJUnit3TestMethodIsPublicVoidNoArg() { doTest(); } + public void testJUnit4TestMethodIsPublicVoidNoArg() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new TestMethodIsPublicVoidNoArgInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package org.junit; " + + "public @interface Test {\n" + + " java.lang.Class<? extends java.lang.Throwable> expected() default org.junit.Test.None.class;" + + "}", + "package junit.framework;" + + "public abstract class TestCase {}"}; + } +} diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/IfCanBeSwitchInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/IfCanBeSwitchInspectionTest.java index 9b1f2574dd77..a13e61bfd234 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/IfCanBeSwitchInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/migration/IfCanBeSwitchInspectionTest.java @@ -15,25 +15,36 @@ */ package com.siyeh.ig.migration; +import com.intellij.codeInspection.InspectionProfileEntry; 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.intellij.testFramework.LightProjectDescriptor; import com.siyeh.ig.IGInspectionTestCase; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public class IfCanBeSwitchInspectionTest extends IGInspectionTestCase { +public class IfCanBeSwitchInspectionTest extends LightInspectionTestCase { - @Override - protected Sdk getTestProjectSdk() { - LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7); - return IdeaTestUtil.getMockJdk17(); + public void testIfCanBeSwitch() throws Exception { + doTest(); } - public void test() throws Exception { + @Nullable + @Override + protected InspectionProfileEntry getInspection() { final IfCanBeSwitchInspection inspection = new IfCanBeSwitchInspection(); inspection.suggestIntSwitches = true; + inspection.suggestEnumSwitches = true; inspection.setOnlySuggestNullSafe(true); - doTest("com/siyeh/igtest/migration/if_switch", new LocalInspectionToolWrapper(inspection)); + return inspection; + } + + @Override + protected String getBasePath() { + return "/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/if_switch"; } } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionTest.java index e408509b51d5..6479236acbb3 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/InstanceMethodNamingConventionInspectionTest.java @@ -24,6 +24,14 @@ import com.siyeh.ig.LightInspectionTestCase; public class InstanceMethodNamingConventionInspectionTest extends LightInspectionTestCase { @Override + protected void setUp() throws Exception { + super.setUp(); + final NativeMethodNamingConventionInspection inspection = new NativeMethodNamingConventionInspection(); + inspection.m_minLength = 0; + myFixture.enableInspections(inspection); + } + + @Override protected InspectionProfileEntry getInspection() { return new InstanceMethodNamingConventionInspection(); } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java index 2ca586feef18..cc20bb3cc8fb 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.naming.com.siyeh.ig.naming; +package com.siyeh.ig.naming; import com.intellij.codeInspection.InspectionProfileEntry; import com.siyeh.ig.LightInspectionTestCase; diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionTest.java index 53e2b6a37f87..5c1eb29822c9 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/StaticMethodNamingConventionInspectionTest.java @@ -24,6 +24,14 @@ import com.siyeh.ig.LightInspectionTestCase; public class StaticMethodNamingConventionInspectionTest extends LightInspectionTestCase { @Override + protected void setUp() throws Exception { + super.setUp(); + final NativeMethodNamingConventionInspection inspection = new NativeMethodNamingConventionInspection(); + inspection.m_minLength = 0; + myFixture.enableInspections(inspection); + } + + @Override protected InspectionProfileEntry getInspection() { return new StaticMethodNamingConventionInspection(); } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/PointlessArithmeticExpressionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/PointlessArithmeticExpressionInspectionTest.java index 48914c37605f..58bbf452bd9c 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/PointlessArithmeticExpressionInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/PointlessArithmeticExpressionInspectionTest.java @@ -1,11 +1,18 @@ package com.siyeh.ig.numeric; -import com.siyeh.ig.IGInspectionTestCase; +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; -public class PointlessArithmeticExpressionInspectionTest extends IGInspectionTestCase { +public class PointlessArithmeticExpressionInspectionTest extends LightInspectionTestCase { - public void test() throws Exception { - doTest("com/siyeh/igtest/numeric/pointless_arithmetic_expression", - new PointlessArithmeticExpressionInspection()); + public void testPointlessArithmeticExpression() { + doTest(); + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new PointlessArithmeticExpressionInspection(); } }
\ No newline at end of file diff --git a/plugins/ShortcutPromoter/src/com/intellij/promoter/ShortcutPromoterManager.java b/plugins/ShortcutPromoter/src/com/intellij/promoter/ShortcutPromoterManager.java index 02356825404b..227d96245080 100644 --- a/plugins/ShortcutPromoter/src/com/intellij/promoter/ShortcutPromoterManager.java +++ b/plugins/ShortcutPromoter/src/com/intellij/promoter/ShortcutPromoterManager.java @@ -15,6 +15,7 @@ import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.io.File; import java.util.HashMap; +import java.util.LinkedHashMap; /** * @author Konstantin Bulenkov @@ -29,7 +30,7 @@ import java.util.HashMap; ) public class ShortcutPromoterManager implements ApplicationComponent, AnActionListener, ExportableApplicationComponent, PersistentStateComponent<Element> { - private final HashMap<String, PromoterState> myState = new HashMap<String, PromoterState>(); + private final HashMap<String, PromoterState> myState = new LinkedHashMap<String, PromoterState>(); private final HashMap<String, ShortcutPromoterEP> myExtensions = new HashMap<String, ShortcutPromoterEP>(); @Override @@ -96,6 +97,10 @@ public class ShortcutPromoterManager implements ApplicationComponent, AnActionLi @Nullable @Override public Element getState() { + if (myState.isEmpty()) { + return null; + } + final Element actions = new Element("actions"); for (String id : myState.keySet()) { final Element action = new Element("action"); diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunner.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunner.java index 1398718e293a..d66e041f1f16 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunner.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunner.java @@ -23,7 +23,6 @@ import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.GenericProgramRunner; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,10 +31,7 @@ public class AntRunner extends GenericProgramRunner { @Nullable @Override - protected RunContentDescriptor doExecute(@NotNull Project project, - @NotNull RunProfileState state, - @Nullable RunContentDescriptor contentToReuse, - @NotNull ExecutionEnvironment environment) throws ExecutionException { + protected RunContentDescriptor doExecute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) throws ExecutionException { FileDocumentManager.getInstance().saveAllDocuments(); state.execute(environment.getExecutor(), this); return null; diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntToolWindowFactory.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntToolWindowFactory.java index 02d8f0696e7f..1a75326f2959 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntToolWindowFactory.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntToolWindowFactory.java @@ -16,6 +16,7 @@ package com.intellij.lang.ant.config.impl; import com.intellij.lang.ant.config.explorer.AntExplorer; +import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.ToolWindow; @@ -27,7 +28,7 @@ import org.jetbrains.annotations.NotNull; /** * @author yole */ -public class AntToolWindowFactory implements ToolWindowFactory { +public class AntToolWindowFactory implements ToolWindowFactory, DumbAware{ @Override public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { AntExplorer explorer = new AntExplorer(project); diff --git a/plugins/copyright/src/META-INF/plugin.xml b/plugins/copyright/src/META-INF/plugin.xml index 8d0c4b038d85..594c28e20966 100644 --- a/plugins/copyright/src/META-INF/plugin.xml +++ b/plugins/copyright/src/META-INF/plugin.xml @@ -11,7 +11,7 @@ <depends optional="true" config-file="java.xml">com.intellij.modules.java</depends> <extensions defaultExtensionNs="com.intellij"> - <projectConfigurable groupId="editor" dynamic="true" displayName="Copyright" instance="com.maddyhome.idea.copyright.ui.CopyrightProjectConfigurable"/> + <projectConfigurable groupId="editor" groupWeight="110" dynamic="true" displayName="Copyright" instance="com.maddyhome.idea.copyright.ui.CopyrightProjectConfigurable"/> <errorHandler implementation="com.intellij.diagnostic.ITNReporter"/> <checkinHandlerFactory implementation="com.maddyhome.idea.copyright.actions.UpdateCopyrightCheckinHandlerFactory"/> <applicationService serviceInterface="com.maddyhome.idea.copyright.util.FileTypeUtil" diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightProfilesPanel.java b/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightProfilesPanel.java index 20ef5847f156..bdbe32db040b 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightProfilesPanel.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightProfilesPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 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. @@ -16,12 +16,13 @@ package com.maddyhome.idea.copyright.ui; -import com.intellij.ide.actions.OpenProjectFileChooserDescriptor; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonShortcuts; import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.fileChooser.FileChooser; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; @@ -33,6 +34,7 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.PopupStep; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; @@ -200,34 +202,26 @@ public class CopyrightProfilesPanel extends MasterDetailsComponent implements Se result.add(new AnAction("Import", "Import", PlatformIcons.IMPORT_ICON) { @Override public void actionPerformed(AnActionEvent event) { - final OpenProjectFileChooserDescriptor descriptor = new OpenProjectFileChooserDescriptor(true) { - @Override - public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) { - return super.isFileVisible(file, showHiddenFiles) || canContainCopyright(file); - } - - @Override - public boolean isFileSelectable(VirtualFile file) { - return super.isFileSelectable(file) || canContainCopyright(file); - } - - private boolean canContainCopyright(VirtualFile file) { - return !file.isDirectory() && (file.getFileType() == StdFileTypes.IDEA_MODULE || file.getFileType() == StdFileTypes.XML); - } - }; - descriptor.setTitle("Choose file containing copyright notice"); + FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor() + .withFileFilter(new Condition<VirtualFile>() { + @Override + public boolean value(VirtualFile file) { + return file.getFileType() == StdFileTypes.IDEA_MODULE || file.getFileType() == StdFileTypes.XML; + } + }) + .withTitle("Choose file containing copyright notice"); FileChooser.chooseFile(descriptor, myProject, null, new Consumer<VirtualFile>() { @Override public void consume(VirtualFile file) { - final List<CopyrightProfile> copyrightProfiles = ExternalOptionHelper.loadOptions(VfsUtilCore.virtualToIoFile(file)); - if (copyrightProfiles == null) return; - if (!copyrightProfiles.isEmpty()) { - if (copyrightProfiles.size() == 1) { - importProfile(copyrightProfiles.get(0)); + final List<CopyrightProfile> profiles = ExternalOptionHelper.loadOptions(VfsUtilCore.virtualToIoFile(file)); + if (profiles == null) return; + if (!profiles.isEmpty()) { + if (profiles.size() == 1) { + importProfile(profiles.get(0)); } else { JBPopupFactory.getInstance() - .createListPopup(new BaseListPopupStep<CopyrightProfile>("Choose profile to import", copyrightProfiles) { + .createListPopup(new BaseListPopupStep<CopyrightProfile>("Choose profile to import", profiles) { @Override public PopupStep onChosen(final CopyrightProfile selectedValue, boolean finalChoice) { return doFinalStep(new Runnable() { @@ -243,7 +237,8 @@ public class CopyrightProfilesPanel extends MasterDetailsComponent implements Se public String getTextFor(CopyrightProfile value) { return value.getName(); } - }).showUnderneathOf(myNorthPanel); + }) + .showUnderneathOf(myNorthPanel); } } else { diff --git a/plugins/cvs/javacvs-src/org/netbeans/lib/cvsclient/ConnectionStreams.java b/plugins/cvs/javacvs-src/org/netbeans/lib/cvsclient/ConnectionStreams.java index d5e89f20dbb3..5484909b35f0 100644 --- a/plugins/cvs/javacvs-src/org/netbeans/lib/cvsclient/ConnectionStreams.java +++ b/plugins/cvs/javacvs-src/org/netbeans/lib/cvsclient/ConnectionStreams.java @@ -17,7 +17,6 @@ import org.netbeans.lib.cvsclient.file.IReaderFactory; import org.netbeans.lib.cvsclient.file.IWriterFactory; import org.netbeans.lib.cvsclient.io.IStreamLogger; import org.netbeans.lib.cvsclient.util.BugLog; -import org.jetbrains.annotations.NonNls; import java.io.*; import java.util.zip.Deflater; @@ -43,8 +42,6 @@ public final class ConnectionStreams private OutputStream outputStream; private DeflaterOutputStream deflaterOutputStream; private final String myCharset; - @NonNls private static final String UNTIL_HERE_THE_CONTENT_IS_GZIPPED_MESSAGE = "@until here the content is gzipped@"; - @NonNls private static final String FROM_NOW_ON_THE_CONTENT_IS_GZIPPED_MESSAGE = "@from now on the content is gzipped@"; // Setup ================================================================== @@ -111,8 +108,6 @@ public final class ConnectionStreams loggedWriter.flush(); if (deflaterOutputStream != null) { deflaterOutputStream.finish(); - - println(UNTIL_HERE_THE_CONTENT_IS_GZIPPED_MESSAGE, streamLogger.getOutputLogStream()); } loggedOutputStream.flush(); } @@ -155,9 +150,6 @@ public final class ConnectionStreams loggedWriter.flush(); loggedOutputStream.flush(); - println(FROM_NOW_ON_THE_CONTENT_IS_GZIPPED_MESSAGE, streamLogger.getInputLogStream()); - println(FROM_NOW_ON_THE_CONTENT_IS_GZIPPED_MESSAGE, streamLogger.getOutputLogStream()); - deflaterOutputStream = new DeflaterOutputStream(connection.getOutputStream(), new Deflater(6)); setOutputStream(deflaterOutputStream); @@ -179,15 +171,4 @@ public final class ConnectionStreams this.loggedOutputStream = streamLogger.createLoggingOutputStream(outputStream); this.loggedWriter = createWriter(this.loggedOutputStream); } - - private void println(String text, OutputStream outputStream) throws IOException { - final OutputStreamWriter writerNoSpecialEncoding = new OutputStreamWriter(outputStream); - println(text, writerNoSpecialEncoding); - writerNoSpecialEncoding.flush(); - } - - private void println(String text, Writer writer) throws IOException { - writer.write(text); - writer.write('\n'); - } } diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index 0a9501ebef94..ef3688448fda 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -152,6 +152,7 @@ implementationClass="org.jetbrains.idea.devkit.navigation.DescriptionTypeRelatedItemLineMarkerProvider"/> <codeInsight.lineMarkerProvider language="JAVA" implementationClass="org.jetbrains.idea.devkit.navigation.ExtensionPointDeclarationRelatedItemLineMarkerProvider"/> + <codeInsight.implementedAtRuntime implementation="org.jetbrains.idea.devkit.inspections.DevKitImplementedAtRuntimeCondition"/> </extensions> <project-components> diff --git a/plugins/devkit/src/actions/NewActionDialog.java b/plugins/devkit/src/actions/NewActionDialog.java index faa1db563ec2..779929ceb818 100644 --- a/plugins/devkit/src/actions/NewActionDialog.java +++ b/plugins/devkit/src/actions/NewActionDialog.java @@ -26,6 +26,7 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiNameHelper; import com.intellij.ui.ColoredListCellRenderer; import com.intellij.ui.ListSpeedSearch; import com.intellij.ui.SimpleTextAttributes; @@ -247,7 +248,7 @@ public class NewActionDialog extends DialogWrapper implements ActionData { setOKActionEnabled(myActionIdEdit.getText().length() > 0 && myActionNameEdit.getText().length() > 0 && myActionTextEdit.getText().length() > 0 && - (!myActionNameEdit.isEditable() || JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(myActionNameEdit.getText()))); + (!myActionNameEdit.isEditable() || PsiNameHelper.getInstance(myProject).isIdentifier(myActionNameEdit.getText()))); myAnchorBeforeRadio.setEnabled(myActionList.getSelectedValue() != null); myAnchorAfterRadio.setEnabled(myActionList.getSelectedValue() != null); diff --git a/plugins/devkit/src/dom/generator/DomGenPanel.java b/plugins/devkit/src/dom/generator/DomGenPanel.java index e0c21611554b..eaa90acf9e39 100644 --- a/plugins/devkit/src/dom/generator/DomGenPanel.java +++ b/plugins/devkit/src/dom/generator/DomGenPanel.java @@ -16,6 +16,7 @@ package org.jetbrains.idea.devkit.dom.generator; import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.fileChooser.FileTypeDescriptor; import com.intellij.openapi.project.Project; @@ -101,7 +102,8 @@ public class DomGenPanel { } }); myOutputDir = new TextFieldWithBrowseButton(); - myOutputDir.addBrowseFolderListener("Select Output For Generated Files", "", myProject, FileChooserDescriptorFactory.getDirectoryChooserDescriptor("Output For Generated Files")); + FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); + myOutputDir.addBrowseFolderListener("Select Output Directory For Generated Files", "", myProject, descriptor); } public JComponent getComponent() { diff --git a/plugins/devkit/src/inspections/DevKitImplementedAtRuntimeCondition.java b/plugins/devkit/src/inspections/DevKitImplementedAtRuntimeCondition.java new file mode 100644 index 000000000000..3c5aff386203 --- /dev/null +++ b/plugins/devkit/src/inspections/DevKitImplementedAtRuntimeCondition.java @@ -0,0 +1,32 @@ +/* + * 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.devkit.inspections; + +import com.intellij.codeInspection.inheritance.ImplementedAtRuntimeCondition; +import com.intellij.psi.PsiClass; +import com.intellij.psi.util.InheritanceUtil; +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public class DevKitImplementedAtRuntimeCondition extends ImplementedAtRuntimeCondition { + @Override + public boolean isImplementedAtRuntime(@NotNull PsiClass psiClass) { + return DevKitImplicitUsageProvider.isDomElementClass(psiClass) || + InheritanceUtil.isInheritor(psiClass, "com.intellij.jam.JamElement"); + } +} diff --git a/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java b/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java index fa87c70ad337..7aeb7a047046 100644 --- a/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java +++ b/plugins/devkit/src/inspections/DevKitImplicitUsageProvider.java @@ -50,7 +50,7 @@ public class DevKitImplicitUsageProvider implements ImplicitUsageProvider { return false; } - private static boolean isDomElementClass(PsiClass psiClass) { + static boolean isDomElementClass(PsiClass psiClass) { if (psiClass.isEnum() || psiClass.isAnnotationType() || psiClass.hasModifierProperty(PsiModifier.PRIVATE)) { diff --git a/plugins/devkit/src/run/PluginRunConfiguration.java b/plugins/devkit/src/run/PluginRunConfiguration.java index ed0764c5581c..2c7361f8f571 100644 --- a/plugins/devkit/src/run/PluginRunConfiguration.java +++ b/plugins/devkit/src/run/PluginRunConfiguration.java @@ -163,10 +163,10 @@ public class PluginRunConfiguration extends RunConfigurationBase implements Modu prefix = PlatformUtils.WEB_PREFIX; } else if (buildNumber.startsWith("OC")) { - prefix = buildNumber.contains("121") ? "CIDR" : PlatformUtils.APPCODE_PREFIX; + prefix = PlatformUtils.APPCODE_PREFIX; } - else if (buildNumber.startsWith("CP")) { - prefix = PlatformUtils.CPP_PREFIX; + else if (buildNumber.startsWith("CL")) { + prefix = PlatformUtils.CLION_PREFIX; } else if (buildNumber.startsWith("DB")) { prefix = PlatformUtils.DBE_PREFIX; diff --git a/plugins/devkit/testData/inspections/implicitUsage/ImplementedAtRuntimeDomElementImpl.java b/plugins/devkit/testData/inspections/implicitUsage/ImplementedAtRuntimeDomElementImpl.java new file mode 100644 index 000000000000..eb0409eb7f93 --- /dev/null +++ b/plugins/devkit/testData/inspections/implicitUsage/ImplementedAtRuntimeDomElementImpl.java @@ -0,0 +1 @@ +public abstract class ImplementedAtRuntimeDomElementImpl implements com.intellij.util.xml.DomElement {}
\ No newline at end of file diff --git a/plugins/devkit/testData/inspections/implicitUsage/ImplementedAtRuntimeJamElementImpl.java b/plugins/devkit/testData/inspections/implicitUsage/ImplementedAtRuntimeJamElementImpl.java new file mode 100644 index 000000000000..27dfb2d006fa --- /dev/null +++ b/plugins/devkit/testData/inspections/implicitUsage/ImplementedAtRuntimeJamElementImpl.java @@ -0,0 +1 @@ +public abstract class ImplementedAtRuntimeJamElementImpl implements com.intellij.jam.JamElement {}
\ No newline at end of file diff --git a/plugins/devkit/testSources/inspections/DevKitImplicitUsageProviderTest.java b/plugins/devkit/testSources/inspections/DevKitImplicitUsageProviderTest.java index bf33c2174159..a7fedaeaa74d 100644 --- a/plugins/devkit/testSources/inspections/DevKitImplicitUsageProviderTest.java +++ b/plugins/devkit/testSources/inspections/DevKitImplicitUsageProviderTest.java @@ -20,6 +20,7 @@ import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection; import com.intellij.openapi.application.PluginPathManager; import com.intellij.testFramework.TestDataPath; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import com.siyeh.ig.inheritance.AbstractClassNeverImplementedInspection; @TestDataPath("$CONTENT_ROOT/testData/inspections/implicitUsage") public class DevKitImplicitUsageProviderTest extends LightCodeInsightFixtureTestCase { @@ -37,14 +38,35 @@ public class DevKitImplicitUsageProviderTest extends LightCodeInsightFixtureTest myFixture.addClass("package com.intellij.util.xml; public interface DomElementVisitor {}"); myFixture.addClass("package com.intellij.util.xml; public interface GenericAttributeValue<T> extends DomElement {}"); - myFixture.enableInspections(new UnusedSymbolLocalInspection(), new UnusedDeclarationInspection()); + myFixture.addClass("package com.intellij.jam; public interface JamElement {}"); } public void testImplicitUsagesDomElement() { + enableImplicitUsageInspections(); myFixture.testHighlighting("ImplicitUsagesDomElement.java"); } public void testImplicitUsagesDomElementVisitor() { + enableImplicitUsageInspections(); myFixture.testHighlighting("ImplicitUsagesDomElementVisitor.java"); } + + private void enableImplicitUsageInspections() { + myFixture.enableInspections(new UnusedSymbolLocalInspection(), new UnusedDeclarationInspection()); + } + + + public void testImplementedAtRuntimeDomElementImpl() { + enableImplementedAtRuntimeInspections(); + myFixture.testHighlighting("ImplementedAtRuntimeDomElementImpl.java"); + } + + public void testImplementedAtRuntimeJamElementImpl() { + enableImplementedAtRuntimeInspections(); + myFixture.testHighlighting("ImplementedAtRuntimeJamElementImpl.java"); + } + + private void enableImplementedAtRuntimeInspections() { + myFixture.enableInspections(new AbstractClassNeverImplementedInspection()); + } } diff --git a/plugins/eclipse/testData/iml/allProps/expected/expected.iml b/plugins/eclipse/testData/iml/allProps/expected/expected.iml index 142bc1072c84..d47060bab059 100644 --- a/plugins/eclipse/testData/iml/allProps/expected/expected.iml +++ b/plugins/eclipse/testData/iml/allProps/expected/expected.iml @@ -92,7 +92,7 @@ <orderEntry type="module-library"> <library name="junit3"> <CLASSES> - <root url="jar://$JUNIT$/lib/junit.jar!/" /> + <root url="jar://$JUNIT$/junit.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES /> @@ -101,7 +101,7 @@ <orderEntry type="module-library"> <library name="junit4"> <CLASSES> - <root url="jar://$JUNIT$/lib/junit-4.11.jar!/" /> + <root url="jar://$JUNIT$/junit-4.11.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES /> diff --git a/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseImlTest.java b/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseImlTest.java index 5e1cc3f87921..4b64e08f04d6 100644 --- a/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseImlTest.java +++ b/plugins/eclipse/testSources/org/jetbrains/idea/eclipse/EclipseImlTest.java @@ -22,8 +22,8 @@ package org.jetbrains.idea.eclipse; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathMacros; -import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.PluginPathManager; +import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.components.PathMacroManager; import com.intellij.openapi.module.Module; @@ -38,8 +38,7 @@ import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.testFramework.IdeaTestCase; -import junit.framework.Assert; -import org.jdom.Document; +import com.intellij.testFramework.PlatformTestUtil; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.idea.eclipse.conversion.EclipseClasspathReader; @@ -49,7 +48,7 @@ import java.util.ArrayList; import java.util.HashSet; public class EclipseImlTest extends IdeaTestCase { - @NonNls public static final String JUNIT = "JUNIT"; + @NonNls private static final String JUNIT = "JUNIT"; @Override protected void setUp() throws Exception { @@ -75,11 +74,8 @@ public class EclipseImlTest extends IdeaTestCase { if (!SystemInfo.isWindows) { fileText = fileText.replaceAll(EclipseXml.FILE_PROTOCOL + "/", EclipseXml.FILE_PROTOCOL); } - String communityAppDir = PathManager.getHomePath(); - if (new File(PathManager.getHomePath(), "community").exists()) { - communityAppDir += "/community"; - } - fileText = fileText.replaceAll("\\$" + JUNIT + "\\$", communityAppDir); + String communityLib = FileUtil.toSystemIndependentName(PathManagerEx.findFileUnderCommunityHome("lib").getAbsolutePath()); + fileText = fileText.replaceAll("\\$" + JUNIT + "\\$", communityLib); final Element classpathElement = JDOMUtil.loadDocument(fileText).getRootElement(); final Module module = WriteCommandAction.runWriteCommandAction(null, new Computable<Module>() { @Override @@ -104,15 +100,14 @@ public class EclipseImlTest extends IdeaTestCase { final Element actualImlElement = new Element("root"); ((ModuleRootManagerImpl)ModuleRootManager.getInstance(module)).getState().writeExternal(actualImlElement); - PathMacros.getInstance().setMacro(JUNIT, communityAppDir); + PathMacros.getInstance().setMacro(JUNIT, communityLib); PathMacroManager.getInstance(module).collapsePaths(actualImlElement); PathMacroManager.getInstance(project).collapsePaths(actualImlElement); PathMacros.getInstance().removeMacro(JUNIT); final Element expectedIml = JDOMUtil.loadDocument(new File(project.getBaseDir().getPath() + "/expected", "expected.iml")).getRootElement(); - Assert.assertTrue(new String(JDOMUtil.printDocument(new Document(actualImlElement), "\n")), - JDOMUtil.areElementsEqual(expectedIml, actualImlElement)); + PlatformTestUtil.assertElementsEqual(expectedIml, actualImlElement); } diff --git a/plugins/git4idea/src/git4idea/GitTaskHandler.java b/plugins/git4idea/src/git4idea/GitTaskHandler.java index 7dac4654d860..5d88d526e038 100644 --- a/plugins/git4idea/src/git4idea/GitTaskHandler.java +++ b/plugins/git4idea/src/git4idea/GitTaskHandler.java @@ -54,6 +54,11 @@ public class GitTaskHandler extends VcsTaskHandler { } @Override + public boolean isEnabled(Project project) { + return !myRepositoryManager.getRepositories().isEmpty(); + } + + @Override public TaskInfo startNewTask(final String taskName) { List<GitRepository> repositories = myRepositoryManager.getRepositories(); List<GitRepository> problems = ContainerUtil.filter(repositories, new Condition<GitRepository>() { diff --git a/plugins/git4idea/src/git4idea/commands/GitSSHGUIHandler.java b/plugins/git4idea/src/git4idea/commands/GitSSHGUIHandler.java index 4d1c13415ec2..9d337971c1e7 100644 --- a/plugins/git4idea/src/git4idea/commands/GitSSHGUIHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitSSHGUIHandler.java @@ -16,6 +16,8 @@ package git4idea.commands; import com.intellij.ide.passwordSafe.ui.PasswordSafePromptDialog; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; @@ -28,7 +30,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.text.JTextComponent; import java.awt.*; -import java.lang.reflect.InvocationTargetException; import java.util.Vector; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -56,11 +57,11 @@ public class GitSSHGUIHandler { message = GitBundle.message("ssh.changed.host.key", hostname, port, fingerprint, serverHostKeyAlgorithm); } final AtomicBoolean rc = new AtomicBoolean(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { + ApplicationManager.getApplication().invokeAndWait(new Runnable() { public void run() { rc.set(Messages.YES == Messages.showYesNoDialog(myProject, message, GitBundle.getString("ssh.confirm.key.titile"), null)); } - }); + }, ModalityState.any()); return rc.get(); } @@ -84,11 +85,11 @@ public class GitSSHGUIHandler { private String processLastError(boolean resetPassword, final String lastError) { String error; if (lastError != null && lastError.length() != 0 && !resetPassword) { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { + ApplicationManager.getApplication().invokeAndWait(new Runnable() { public void run() { showError(lastError); } - }); + }, ModalityState.any()); error = null; } else { @@ -124,25 +125,17 @@ public class GitSSHGUIHandler { final Vector<Boolean> echo, final String lastError) { final AtomicReference<Vector<String>> rc = new AtomicReference<Vector<String>>(); - try { - EventQueue.invokeAndWait(new Runnable() { - public void run() { - showError(lastError); - GitSSHKeyboardInteractiveDialog dialog = - new GitSSHKeyboardInteractiveDialog(name, numPrompts, instruction, prompt, echo, username); - dialog.show(); - if (dialog.isOK()) { - rc.set(dialog.getResults()); - } + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + public void run() { + showError(lastError); + GitSSHKeyboardInteractiveDialog dialog = + new GitSSHKeyboardInteractiveDialog(name, numPrompts, instruction, prompt, echo, username); + dialog.show(); + if (dialog.isOK()) { + rc.set(dialog.getResults()); } - }); - } - catch (InterruptedException e) { - throw new RuntimeException("dialog failed", e); - } - catch (InvocationTargetException e) { - throw new RuntimeException("dialog failed", e); - } + } + }, ModalityState.any()); return rc.get(); } diff --git a/plugins/git4idea/src/git4idea/log/GitBekParentFixer.java b/plugins/git4idea/src/git4idea/log/GitBekParentFixer.java index 054ed9f90b48..4bcfade3cfa8 100644 --- a/plugins/git4idea/src/git4idea/log/GitBekParentFixer.java +++ b/plugins/git4idea/src/git4idea/log/GitBekParentFixer.java @@ -126,6 +126,12 @@ class GitBekParentFixer { @Nullable @Override + public VcsLogHashFilter getHashFilter() { + return null; + } + + @Nullable + @Override public VcsLogStructureFilter getStructureFilter() { return null; } diff --git a/plugins/git4idea/src/git4idea/log/GitLogProvider.java b/plugins/git4idea/src/git4idea/log/GitLogProvider.java index 435313fa5c7d..b5096a94f03b 100644 --- a/plugins/git4idea/src/git4idea/log/GitLogProvider.java +++ b/plugins/git4idea/src/git4idea/log/GitLogProvider.java @@ -308,7 +308,7 @@ public class GitLogProvider implements VcsLogProvider { } if (filterCollection.getTextFilter() != null) { - String textFilter = StringUtil.escapeBackSlashes(filterCollection.getTextFilter().getText()); + String textFilter = filterCollection.getTextFilter().getText(); filterParameters.add(prepareParameter("grep", textFilter)); } diff --git a/plugins/git4idea/src/git4idea/push/GitPusher.java b/plugins/git4idea/src/git4idea/push/GitPusher.java index 778d2dcd0033..1dfcdfaf327d 100644 --- a/plugins/git4idea/src/git4idea/push/GitPusher.java +++ b/plugins/git4idea/src/git4idea/push/GitPusher.java @@ -256,7 +256,7 @@ public final class GitPusher { @NotNull GitCommitsByRepoAndBranch commits, @NotNull GitRepository repository) { GitPushSpec pushSpec = pushInfo.getPushSpecs().get(repository); - GitSimplePushResult simplePushResult = pushAndGetSimpleResult(repository, pushSpec, commits.get(repository)); + GitSimplePushResult simplePushResult = pushAndGetSimpleResult(repository, pushSpec); String output = simplePushResult.getOutput(); switch (simplePushResult.getType()) { case SUCCESS: @@ -306,8 +306,7 @@ public final class GitPusher { } @NotNull - private GitSimplePushResult pushAndGetSimpleResult(@NotNull GitRepository repository, - @NotNull GitPushSpec pushSpec, @NotNull GitCommitsByBranch commitsByBranch) { + private GitSimplePushResult pushAndGetSimpleResult(@NotNull GitRepository repository, @NotNull GitPushSpec pushSpec) { if (pushSpec.getDest() == NO_TARGET_BRANCH) { return GitSimplePushResult.notPushed(); } @@ -367,21 +366,6 @@ public final class GitPusher { } @NotNull - private static String formPushSpec(@NotNull GitPushSpec spec, @NotNull GitRemote remote) { - String destWithRemote = spec.getDest().getName(); - String prefix = remote.getName() + "/"; - String destName; - if (destWithRemote.startsWith(prefix)) { - destName = destWithRemote.substring(prefix.length()); - } - else { - LOG.error("Destination remote branch has invalid name. Remote branch name: " + destWithRemote + "\nRemote: " + remote); - destName = destWithRemote; - } - return spec.getSource().getName() + ":" + destName; - } - - @NotNull private GitSimplePushResult pushNatively(GitRepository repository, GitPushSpec pushSpec, @NotNull String url) { GitPushRejectedDetector rejectedDetector = new GitPushRejectedDetector(); GitLineHandlerListener progressListener = GitStandardProgressAnalyzer.createListener(myProgressIndicator); diff --git a/plugins/git4idea/test-stepdefs/git4idea/GitCherryPickStepdefs.java b/plugins/git4idea/test-stepdefs/git4idea/GitCherryPickStepdefs.java index 2fe42a0d76a1..553cf260e268 100644 --- a/plugins/git4idea/test-stepdefs/git4idea/GitCherryPickStepdefs.java +++ b/plugins/git4idea/test-stepdefs/git4idea/GitCherryPickStepdefs.java @@ -17,8 +17,7 @@ package git4idea; import com.google.common.base.Function; import com.google.common.collect.Collections2; -import com.intellij.dvcs.test.MockVcsHelper; -import com.intellij.dvcs.test.MockVirtualFile; +import com.intellij.mock.MockVirtualFile; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.text.StringUtil; @@ -40,6 +39,7 @@ import cucumber.annotation.en.Then; import cucumber.annotation.en.When; import git4idea.cherrypick.GitCherryPicker; import git4idea.config.GitVersionSpecialty; +import git4idea.test.MockVcsHelper; import java.util.*; diff --git a/plugins/git4idea/test-stepdefs/git4idea/GitCucumberWorld.java b/plugins/git4idea/test-stepdefs/git4idea/GitCucumberWorld.java index 2db213ca1a30..2a521f28db6f 100644 --- a/plugins/git4idea/test-stepdefs/git4idea/GitCucumberWorld.java +++ b/plugins/git4idea/test-stepdefs/git4idea/GitCucumberWorld.java @@ -15,7 +15,6 @@ */ package git4idea; -import com.intellij.dvcs.test.MockVcsHelper; import com.intellij.idea.IdeaTestApplication; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ProjectComponent; @@ -46,6 +45,7 @@ import git4idea.repo.GitRepository; import git4idea.test.GitExecutor; import git4idea.test.GitHttpAuthTestService; import git4idea.test.GitTestUtil; +import git4idea.test.MockVcsHelper; import org.jetbrains.annotations.NotNull; import org.junit.Assert; import org.picocontainer.MutablePicoContainer; diff --git a/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderTest.java b/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderTest.java index b8bce9b7ee82..7c233195a7f2 100644 --- a/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderTest.java +++ b/plugins/git4idea/tests/git4idea/repo/GitRepositoryReaderTest.java @@ -54,7 +54,7 @@ public class GitRepositoryReaderTest extends GitPlatformTest { }); } - @SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors", "UnusedParameters"}) + @SuppressWarnings({"UnusedParameters"}) public GitRepositoryReaderTest(@NotNull String name, @NotNull File testDir) { myTestCaseDir = testDir; } diff --git a/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java b/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java index c02ec553dd8f..b433a5b8a0bf 100644 --- a/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java +++ b/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java @@ -30,6 +30,7 @@ import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; import com.intellij.testFramework.vcs.AbstractVcsTestCase; +import com.intellij.util.ArrayUtil; import com.intellij.util.ObjectUtils; import git4idea.DialogManager; import git4idea.GitPlatformFacade; @@ -43,6 +44,7 @@ import git4idea.repo.GitRepositoryManager; import org.jetbrains.annotations.NotNull; import java.io.IOException; +import java.util.*; public abstract class GitPlatformTest extends UsefulTestCase { @@ -157,13 +159,20 @@ public abstract class GitPlatformTest extends UsefulTestCase { } private void enableDebugLogging() { - TestLoggerFactory.enableDebugLogging(myTestRootDisposable, "#" + Executor.class.getName(), - "#" + GitHandler.class.getName(), - GitHandler.class.getName()); + List<String> commonCategories = new ArrayList<String>(Arrays.asList("#" + Executor.class.getName(), + "#" + GitHandler.class.getName(), + GitHandler.class.getName())); + commonCategories.addAll(getDebugLogCategories()); + TestLoggerFactory.enableDebugLogging(myTestRootDisposable, ArrayUtil.toStringArray(commonCategories)); myTestStartedIndicator = createTestStartedIndicator(); LOG.info(myTestStartedIndicator); } + @NotNull + protected Collection<String> getDebugLogCategories() { + return Collections.emptyList(); + } + @Override protected void defaultRunBare() throws Throwable { try { diff --git a/plugins/git4idea/tests/git4idea/test/MockVcsHelper.java b/plugins/git4idea/tests/git4idea/test/MockVcsHelper.java new file mode 100644 index 000000000000..45f1e3965bea --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/MockVcsHelper.java @@ -0,0 +1,225 @@ +/* + * 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 git4idea.test; + +import com.intellij.ide.errorTreeView.HotfixData; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.*; +import com.intellij.openapi.vcs.annotate.AnnotationProvider; +import com.intellij.openapi.vcs.annotate.FileAnnotation; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.CommitResultHandler; +import com.intellij.openapi.vcs.changes.LocalChangeList; +import com.intellij.openapi.vcs.history.VcsFileRevision; +import com.intellij.openapi.vcs.history.VcsHistoryProvider; +import com.intellij.openapi.vcs.merge.MergeDialogCustomizer; +import com.intellij.openapi.vcs.merge.MergeProvider; +import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings; +import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.io.File; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class MockVcsHelper extends AbstractVcsHelper { + private volatile boolean myCommitDialogShown; + private volatile boolean myMergeDialogShown; + + private CommitHandler myCommitHandler; + private MergeHandler myMergeHandler; + + public MockVcsHelper(@NotNull Project project) { + super(project); + } + + @Override + public void showErrors(List<VcsException> abstractVcsExceptions, @NotNull String tabDisplayName) { + throw new UnsupportedOperationException(); + } + + @Override + public void showErrors(Map<HotfixData, List<VcsException>> exceptionGroups, @NotNull String tabDisplayName) { + throw new UnsupportedOperationException(); + } + + @Override + public List<VcsException> runTransactionRunnable(AbstractVcs vcs, TransactionRunnable runnable, Object vcsParameters) { + throw new UnsupportedOperationException(); + } + + @Override + public void showAnnotation(FileAnnotation annotation, VirtualFile file, AbstractVcs vcs) { + throw new UnsupportedOperationException(); + } + + @Override + public void showDifferences(VcsFileRevision cvsVersionOn, VcsFileRevision cvsVersionOn1, File file) { + throw new UnsupportedOperationException(); + } + + @Override + public void showChangesListBrowser(CommittedChangeList changelist, @Nls String title) { + throw new UnsupportedOperationException(); + } + + @Override + public void showChangesBrowser(List<CommittedChangeList> changelists) { + throw new UnsupportedOperationException(); + } + + @Override + public void showChangesBrowser(List<CommittedChangeList> changelists, @Nls String title) { + throw new UnsupportedOperationException(); + } + + @Override + public void showChangesBrowser(CommittedChangesProvider provider, + RepositoryLocation location, + @Nls String title, + @Nullable Component parent) { + throw new UnsupportedOperationException(); + } + + @Override + public void showWhatDiffersBrowser(@Nullable Component parent, Collection<Change> changes, @Nls String title) { + throw new UnsupportedOperationException(); + } + + @Override + public <T extends CommittedChangeList, U extends ChangeBrowserSettings> T chooseCommittedChangeList(@NotNull CommittedChangesProvider<T, U> provider, + RepositoryLocation location) { + throw new UnsupportedOperationException(); + } + + @Override + public void openCommittedChangesTab(AbstractVcs vcs, VirtualFile root, ChangeBrowserSettings settings, int maxCount, String title) { + throw new UnsupportedOperationException(); + } + + @Override + public void openCommittedChangesTab(CommittedChangesProvider provider, + RepositoryLocation location, + ChangeBrowserSettings settings, + int maxCount, + String title) { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public List<VirtualFile> showMergeDialog(List<VirtualFile> files, + MergeProvider provider, + @NotNull MergeDialogCustomizer mergeDialogCustomizer) { + myMergeDialogShown = true; + if (myMergeHandler != null) { + myMergeHandler.showMergeDialog(); + } + return Collections.emptyList(); + } + + public boolean mergeDialogWasShown() { + return myMergeDialogShown; + } + + @Override + public void showFileHistory(VcsHistoryProvider vcsHistoryProvider, FilePath path, AbstractVcs vcs, String repositoryPath) { + throw new UnsupportedOperationException(); + } + + @Override + public void showFileHistory(VcsHistoryProvider vcsHistoryProvider, + AnnotationProvider annotationProvider, + FilePath path, + String repositoryPath, + AbstractVcs vcs) { + throw new UnsupportedOperationException(); + } + + @Override + public void showRollbackChangesDialog(List<Change> changes) { + throw new UnsupportedOperationException(); + } + + @Override + public Collection<VirtualFile> selectFilesToProcess(List<VirtualFile> files, + String title, + @Nullable String prompt, + String singleFileTitle, + String singleFilePromptTemplate, + VcsShowConfirmationOption confirmationOption) { + throw new UnsupportedOperationException(); + } + + @Override + public Collection<FilePath> selectFilePathsToProcess(List<FilePath> files, + String title, + @Nullable String prompt, + String singleFileTitle, + String singleFilePromptTemplate, + VcsShowConfirmationOption confirmationOption) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean commitChanges(@NotNull Collection<Change> changes, @NotNull LocalChangeList initialChangeList, + @NotNull String commitMessage, @Nullable CommitResultHandler customResultHandler) { + myCommitDialogShown = true; + if (myCommitHandler != null) { + boolean success = myCommitHandler.commit(commitMessage); + if (customResultHandler != null) { + if (success) { + customResultHandler.onSuccess(commitMessage); + } + else { + customResultHandler.onFailure(); + } + } + return success; + } + if (customResultHandler != null) { + customResultHandler.onFailure(); + } + return false; + } + + public void registerHandler(CommitHandler handler) { + myCommitHandler = handler; + } + + public void registerHandler(MergeHandler handler) { + myMergeHandler = handler; + } + + public boolean commitDialogWasShown() { + return myCommitDialogShown; + } + + public interface CommitHandler { + boolean commit(String commitMessage); + } + + public interface MergeHandler { + void showMergeDialog(); + } + +} diff --git a/plugins/git4idea/tests/git4idea/test/MockVirtualFile.java b/plugins/git4idea/tests/git4idea/test/MockVirtualFile.java new file mode 100644 index 000000000000..e3f0a3afe071 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/MockVirtualFile.java @@ -0,0 +1,162 @@ +/* + * 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 git4idea.test; + +import com.intellij.mock.MockVirtualFileSystem; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileSystem; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * VirtualFile implementation for tests based on {@link java.io.File}. + * Not reusing {@link com.intellij.mock.MockVirtualFile}, because the latter holds everything in memory, which is fast, but requires + * synchronization with the real file system. + */ +public class MockVirtualFile extends VirtualFile { + + private static final VirtualFileSystem ourFileSystem = new MockVirtualFileSystem(); + + private final String myPath; + + public MockVirtualFile(@NotNull String path) { + myPath = FileUtil.toSystemIndependentName(path); + } + + @NotNull + @Override + public String getName() { + return new File(myPath).getName(); + } + + @NotNull + @Override + public VirtualFileSystem getFileSystem() { + return ourFileSystem; + } + + @NotNull + @Override + public String getPath() { + return myPath; + } + + @Override + public boolean isWritable() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isDirectory() { + return new File(myPath).isDirectory(); + } + + @Override + public boolean isValid() { + return new File(myPath).exists(); + } + + @Override + @Nullable + public VirtualFile getParent() { + File parentFile = FileUtil.getParentFile(new File(myPath)); + return parentFile != null ? new MockVirtualFile(parentFile.getPath()) : null; + } + + @Override + public VirtualFile[] getChildren() { + String[] list = new File(myPath).list(); + if (list == null) { + return EMPTY_ARRAY; + } + VirtualFile[] files = new VirtualFile[list.length]; + for (int i = 0; i < list.length; i++) { + files[i] = new MockVirtualFile(myPath + "/" + list[i]); + } + return files; + } + + @NotNull + @Override + public OutputStream getOutputStream(Object requestor, long newModificationStamp, long newTimeStamp) { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public byte[] contentsToByteArray() { + throw new UnsupportedOperationException(); + } + + @Override + public long getTimeStamp() { + throw new UnsupportedOperationException(); + } + + @Override + public long getLength() { + throw new UnsupportedOperationException(); + } + + @Override + public void refresh(boolean asynchronous, boolean recursive, Runnable postRunnable) { + } + + @Override + public InputStream getInputStream() { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + return myPath; + } + + @NotNull + @Override + public String getUrl() { + return myPath; + } + + @NotNull + @Override + public FileType getFileType() { + return FileTypes.PLAIN_TEXT; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MockVirtualFile file = (MockVirtualFile)o; + + return myPath.equals(file.myPath); + } + + @Override + public int hashCode() { + return myPath.hashCode(); + } + +} diff --git a/plugins/git4idea/tests/git4idea/validators/GitRefNameValidatorTest.java b/plugins/git4idea/tests/git4idea/validators/GitRefNameValidatorTest.java index 1b4908f3a41e..c7da36abec88 100644 --- a/plugins/git4idea/tests/git4idea/validators/GitRefNameValidatorTest.java +++ b/plugins/git4idea/tests/git4idea/validators/GitRefNameValidatorTest.java @@ -16,8 +16,12 @@ package git4idea.validators; import com.intellij.util.Function; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import com.intellij.util.containers.ContainerUtil; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Collection; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; @@ -26,52 +30,16 @@ import static org.testng.Assert.assertTrue; * The test for {@link GitRefNameValidator}. * Tests are based on the <a href="http://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html"> * specification of valid Git references</a> - * - * @author Kirill Likhodedov */ +@RunWith(Parameterized.class) public class GitRefNameValidatorTest { - - @DataProvider(name = "valid") - public Object[][] createValidData() { - return new Object[][] { - { "WORD", "branch" }, - { "UNDERSCORED_WORD", "new_branch" }, - { "HIERARCHY", "user/branch" }, - { "HIERARCHY_2", "user/branch/sub_branch" }, - { "BEGINS_WITH_SLASH", "/branch" }, // actual branch name will be with trimmed slash - { "NON_CONS_DOTS", "complex.branch.name" } - }; - } - - @DataProvider(name = "simple_invalid") - public Object[][] createInvalidData() { - return new Object[][] { - { "BEGIN_WITH_DOT", ".branch" }, - { "ONLY_DOT", "." }, - { "ENDS_WITH_SLASH", "branch/" }, - { "ENDS_WITH_DOT", "branch." }, - { "ENDS_WITH_LOCK", "branch.lock" }, - { "TWO_DOTS_1", "branch..name" }, - { "TWO_DOTS_2", "..name" }, - { "TWO_DOTS_3", "..branch" } - }; - } private static final String[] ILLEGAL_CHARS = { " ", "~", "^", ":", "?", "*", "[", "@{", "\\" }; - - @DataProvider(name = "invalid_chars") - public Object[][] createInvalidCharsData() { - return populateWithIllegalChars(ILLEGAL_CHARS, new Function<String, String>() { - @Override public String fun(String s) { - return s; - } - }); - } - - private static final int CONTROL_CHARS_START = 5; // we can't test from 0 to 4 via @DataProvider due to TestNG limitations + private static final int CONTROL_CHARS_START = 0; private static final int CONTROL_CHARS_END = 31; private static final int CONTROL_CHARS_SIZE = CONTROL_CHARS_END - CONTROL_CHARS_START + 1; private static final String[] CONTROL_CHARS = new String[CONTROL_CHARS_SIZE + 1]; // + DEL + static { for (int i = CONTROL_CHARS_START; i <= CONTROL_CHARS_END; i++) { CONTROL_CHARS[i-CONTROL_CHARS_START] = String.valueOf((char)i); @@ -79,8 +47,42 @@ public class GitRefNameValidatorTest { CONTROL_CHARS[CONTROL_CHARS_SIZE] = "\u007F"; // DEL } - @DataProvider(name = "invalid_control_chars") - public Object[][] createInvalidControlCharsData() { + private final String myRefNameToTest; + private final boolean myIsExpectedValid; + + private static Object[][] createValidData() { + return new Object[][] { + { "WORD", "branch" }, + { "UNDERSCORED_WORD", "new_branch" }, + { "HIERARCHY", "user/branch" }, + { "HIERARCHY_2", "user/branch/sub_branch" }, + { "BEGINS_WITH_SLASH", "/branch" }, // actual branch name will be with trimmed slash + { "NON_CONS_DOTS", "complex.branch.name" } + }; + } + + private static Object[][] createInvalidData() { + return new Object[][] { + { "BEGIN_WITH_DOT", ".branch" }, + { "ONLY_DOT", "." }, + { "ENDS_WITH_SLASH", "branch/" }, + { "ENDS_WITH_DOT", "branch." }, + { "ENDS_WITH_LOCK", "branch.lock" }, + { "TWO_DOTS_1", "branch..name" }, + { "TWO_DOTS_2", "..name" }, + { "TWO_DOTS_3", "..branch" } + }; + } + + public static Object[][] createInvalidCharsData() { + return populateWithIllegalChars(ILLEGAL_CHARS, new Function<String, String>() { + @Override public String fun(String s) { + return s; + } + }); + } + + public static Object[][] createInvalidControlCharsData() { return populateWithIllegalChars(CONTROL_CHARS, new Function<String, String>() { @Override public String fun(String s) { Character c = s.charAt(0); @@ -99,34 +101,38 @@ public class GitRefNameValidatorTest { return data; } - @Test(dataProvider = "valid") - public void testValid(String testName, String branchName) { - assertValid(branchName); + @Parameterized.Parameters(name = "{0}") + public static Collection<Object[]> data() { + Collection<Object[]> data = ContainerUtil.newArrayList(); + populateData(data, createValidData(), true); + populateData(data, createInvalidData(), false); + populateData(data, createInvalidCharsData(), false); + populateData(data, createInvalidControlCharsData(), false); + return data; } - @Test(dataProvider = "simple_invalid") - public void testSimpleInvalid(String testName, String branchName) { - assertInvalid(branchName); + private static void populateData(Collection<Object[]> data, Object[][] source, boolean valid) { + for (Object[] testCase : source) { + data.add(new Object[] {testCase[0], testCase[1], valid}); + } } - @Test(dataProvider = "invalid_chars") - public void testInvalidChars(String testName, String branchName) { - assertInvalid(branchName); + @SuppressWarnings("UnusedParameters") + public GitRefNameValidatorTest(String name, String refNameToTest, boolean valid) { + myRefNameToTest = refNameToTest; + myIsExpectedValid = valid; } - @Test(dataProvider = "invalid_control_chars") - public void control_chars_are_invalid(String testName, String branchName) { - assertInvalid(branchName); - } - - // \u0000 to \u0004 can't be passed to the TestNG DataProvider - see org.testng.remote.strprotocol.MessageHelper @Test - public void control_chars_from_0_to_4_are_invalid() { - for (int i = 0; i < 5; i++) { - assertInvalid("bra" + (char)i + "nch"); + public void testAll() { + if (myIsExpectedValid) { + assertValid(myRefNameToTest); + } + else { + assertInvalid(myRefNameToTest); } } - + private static void assertValid(String branchName) { assertTrue(GitRefNameValidator.getInstance().checkInput(branchName), "Should be valid"); assertTrue(GitRefNameValidator.getInstance().canClose(branchName), "Should be valid"); diff --git a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java index 3d3d8201e03a..da64988f5b16 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java @@ -176,7 +176,6 @@ public abstract class GithubTest extends GitPlatformTest { myHttpAuthService = (GitHttpAuthTestService)ServiceManager.getService(GitHttpAuthService.class); - try { beforeTest(); } @@ -197,7 +196,7 @@ public abstract class GithubTest extends GitPlatformTest { afterTest(); } finally { - myHttpAuthService.cleanup(); + if (myHttpAuthService != null) myHttpAuthService.cleanup(); super.tearDown(); } } diff --git a/plugins/gradle/jps-plugin/gradle-jps-plugin.iml b/plugins/gradle/jps-plugin/gradle-jps-plugin.iml index 0d1d5300e84b..03feae393c00 100644 --- a/plugins/gradle/jps-plugin/gradle-jps-plugin.iml +++ b/plugins/gradle/jps-plugin/gradle-jps-plugin.iml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <module type="JAVA_MODULE" version="4"> - <component name="NewModuleRootManager" inherit-compiler-output="true"> + <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="true"> <exclude-output /> <content url="file://$MODULE_DIR$"> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java index 7e182a6eda66..4ec3f9dd7e06 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java @@ -1,26 +1,35 @@ +/* + * 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.plugins.gradle.util; -import com.intellij.ide.actions.OpenProjectFileChooserDescriptor; -import com.intellij.ide.plugins.IdeaPluginDescriptor; -import com.intellij.ide.plugins.PluginManager; -import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.ide.util.PropertiesComponent; -import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.externalSystem.model.ExternalSystemException; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.fileChooser.FileTypeDescriptor; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.containers.Stack; import org.gradle.tooling.model.GradleProject; import org.gradle.tooling.model.gradle.GradleScript; import org.gradle.wrapper.WrapperConfiguration; import org.gradle.wrapper.WrapperExecutor; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,12 +45,9 @@ import java.util.Properties; * @since 8/25/11 1:19 PM */ public class GradleUtil { + private static final String LAST_USED_GRADLE_HOME_KEY = "last.used.gradle.home"; - private static final String LAST_USED_GRADLE_HOME_KEY = "last.used.gradle.home"; - @NonNls private static final String JVM_ARG_FORMAT = "-D%1$s=%2$s"; - - private GradleUtil() { - } + private GradleUtil() { } /** * Allows to retrieve file chooser descriptor that filters gradle scripts. @@ -53,12 +59,12 @@ public class GradleUtil { */ @NotNull public static FileChooserDescriptor getGradleProjectFileChooserDescriptor() { - return DescriptorHolder.GRADLE_BUILD_FILE_CHOOSER_DESCRIPTOR; + return FileChooserDescriptorFactory.createSingleFileDescriptor(GradleConstants.EXTENSION); } @NotNull public static FileChooserDescriptor getGradleHomeFileChooserDescriptor() { - return DescriptorHolder.GRADLE_HOME_FILE_CHOOSER_DESCRIPTOR; + return FileChooserDescriptorFactory.createSingleFolderDescriptor(); } @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") @@ -69,7 +75,7 @@ public class GradleUtil { /** * Tries to retrieve what settings should be used with gradle wrapper for the gradle project located at the given path. * - * @param gradleProjectPath target gradle project config's (*.gradle) path or config file's directory path. + * @param gradleProjectPath target gradle project config (*.gradle) path or config file's directory path. * @return gradle wrapper settings should be used with gradle wrapper for the gradle project located at the given path * if any; <code>null</code> otherwise */ @@ -118,30 +124,6 @@ public class GradleUtil { } /** - * We use this class in order to avoid static initialisation of the wrapped object - it loads number of pico container-based - * dependencies that are unavailable to the slave gradle project, so, we don't want to get unexpected NPE there. - */ - private static class DescriptorHolder { - public static final FileChooserDescriptor GRADLE_BUILD_FILE_CHOOSER_DESCRIPTOR = new OpenProjectFileChooserDescriptor(true) { - @Override - public boolean isFileSelectable(VirtualFile file) { - return file.getName().endsWith(GradleConstants.EXTENSION); - } - - @Override - public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) { - if (!super.isFileVisible(file, showHiddenFiles)) { - return false; - } - return file.isDirectory() || file.getName().endsWith(GradleConstants.EXTENSION); - } - }; - - public static final FileChooserDescriptor GRADLE_HOME_FILE_CHOOSER_DESCRIPTOR - = new FileChooserDescriptor(false, true, false, false, false, false); - } - - /** * Allows to build file system path to the target gradle sub-project given the root project path. * * @param subProject target sub-project which config path we're interested in @@ -242,9 +224,4 @@ public class GradleUtil { return candidates[0]; } - - @NotNull - public static String createJvmArg(@NotNull String name, @NotNull String value) { - return String.format(JVM_ARG_FORMAT, name, value); - } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/AnnotatedMembersSearcher.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/AnnotatedMembersSearcher.java index cf1fe7234f77..eb702e373b59 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/AnnotatedMembersSearcher.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/findUsages/AnnotatedMembersSearcher.java @@ -15,9 +15,7 @@ */ package org.jetbrains.plugins.groovy.findUsages; -import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.psi.impl.search.AnnotatedElementsSearcher; @@ -48,7 +46,12 @@ public class AnnotatedMembersSearcher implements QueryExecutor<PsiModifierListOw @NotNull private static List<PsiModifierListOwner> getAnnotatedMemberCandidates(final PsiClass clazz, final GlobalSearchScope scope) { - final String name = clazz.getName(); + final String name = ApplicationManager.getApplication().runReadAction(new Computable<String>() { + @Override + public String compute() { + return clazz.getName(); + } + }); if (name == null) return Collections.emptyList(); final Collection<PsiElement> members = ApplicationManager.getApplication().runReadAction(new Computable<Collection<PsiElement>>() { @Override @@ -60,14 +63,20 @@ public class AnnotatedMembersSearcher implements QueryExecutor<PsiModifierListOw return Collections.emptyList(); } - final ArrayList<PsiModifierListOwner> result = new ArrayList<PsiModifierListOwner>(); - for (PsiElement element : members) { - if (element instanceof GroovyFile) { - element = ((GroovyFile)element).getPackageDefinition(); - } - if (element instanceof PsiModifierListOwner) { - result.add((PsiModifierListOwner)element); - } + final List<PsiModifierListOwner> result = new ArrayList<PsiModifierListOwner>(); + for (final PsiElement element : members) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + PsiElement e = + element instanceof GroovyFile ? + ((GroovyFile)element).getPackageDefinition() : element; + + if (e instanceof PsiModifierListOwner) { + result.add((PsiModifierListOwner)e); + } + } + }); } return result; } @@ -77,14 +86,12 @@ public class AnnotatedMembersSearcher implements QueryExecutor<PsiModifierListOw final PsiClass annClass = p.getAnnotationClass(); assert annClass.isAnnotationType() : "Annotation type should be passed to annotated members search"; - AccessToken token = ReadAction.start(); - final String annotationFQN; - try { - annotationFQN = annClass.getQualifiedName(); - } - finally { - token.finish(); - } + final String annotationFQN = ApplicationManager.getApplication().runReadAction(new Computable<String>() { + @Override + public String compute() { + return annClass.getQualifiedName(); + } + }); assert annotationFQN != null; final SearchScope scope = p.getScope(); @@ -92,44 +99,49 @@ public class AnnotatedMembersSearcher implements QueryExecutor<PsiModifierListOw final List<PsiModifierListOwner> candidates; if (scope instanceof GlobalSearchScope) { candidates = getAnnotatedMemberCandidates(annClass, ((GlobalSearchScope)scope)); - } else { + } + else { candidates = new ArrayList<PsiModifierListOwner>(); - for (PsiElement element : ((LocalSearchScope)scope).getScope()) { - if (element instanceof GroovyPsiElement) { - ((GroovyPsiElement)element).accept(new GroovyRecursiveElementVisitor() { - @Override - public void visitMethod(GrMethod method) { - candidates.add(method); - } + for (final PsiElement element : ((LocalSearchScope)scope).getScope()) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + if (element instanceof GroovyPsiElement) { + ((GroovyPsiElement)element).accept(new GroovyRecursiveElementVisitor() { + @Override + public void visitMethod(GrMethod method) { + candidates.add(method); + } - @Override - public void visitField(GrField field) { - candidates.add(field); + @Override + public void visitField(GrField field) { + candidates.add(field); + } + }); } - }); - } + } + }); } } - for (PsiModifierListOwner candidate : candidates) { - token = ReadAction.start(); - try { - if (!AnnotatedElementsSearcher.isInstanceof(candidate, p.getTypes())) { - continue; - } - - PsiModifierList list = candidate.getModifierList(); - if (list != null) { - for (PsiAnnotation annotation : list.getAnnotations()) { - if (annotationFQN.equals(annotation.getQualifiedName()) && !consumer.process(candidate)) { - return false; + for (final PsiModifierListOwner candidate : candidates) { + boolean accepted = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>(){ + @Override + public Boolean compute() { + if (AnnotatedElementsSearcher.isInstanceof(candidate, p.getTypes())) { + PsiModifierList list = candidate.getModifierList(); + if (list != null) { + for (PsiAnnotation annotation : list.getAnnotations()) { + if (annotationFQN.equals(annotation.getQualifiedName()) && !consumer.process(candidate)) { + return false; + } + } } } + return true; } - } - finally { - token.finish(); - } + }); + if (!accepted) return false; } return true; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java index 0b82ae756d03..bcba56016d87 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java @@ -447,7 +447,7 @@ public abstract class GrMethodBaseImpl extends GrStubElementBase<GrMethodStub> i GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(nameElement.getProject()); PsiElement newNameElement; - if (JavaPsiFacade.getInstance(getProject()).getNameHelper().isIdentifier(name)) { + if (PsiNameHelper.getInstance(getProject()).isIdentifier(name)) { try { GrMethod method = factory.createMethod(name, null); newNameElement = method.getNameIdentifierGroovy(); diff --git a/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovycRunner.java b/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovycRunner.java index aaa42bca43c3..6e464d6c2642 100644 --- a/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovycRunner.java +++ b/plugins/groovy/rt/src/org/jetbrains/groovy/compiler/rt/GroovycRunner.java @@ -100,6 +100,9 @@ public class GroovycRunner { method.invoke(null, forStubs, argPath); } catch (Throwable e) { + while (e.getCause() != null) { + e = e.getCause(); + } e.printStackTrace(); System.exit(1); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyCreateClassDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyCreateClassDialog.java index c7a2c3ae4625..5ed50b62efef 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyCreateClassDialog.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GroovyCreateClassDialog.java @@ -99,7 +99,7 @@ public class GroovyCreateClassDialog extends DialogWrapper { myPackageTextField.getDocument().addDocumentListener(new DocumentAdapter() { @Override public void documentChanged(DocumentEvent e) { - PsiNameHelper nameHelper = JavaPsiFacade.getInstance(myProject).getNameHelper(); + PsiNameHelper nameHelper = PsiNameHelper.getInstance(myProject); String packageName = getPackageName(); getOKAction().setEnabled(nameHelper.isQualifiedName(packageName) || packageName != null && packageName.isEmpty()); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightHandlerFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightHandlerFactory.java index 811f8caec379..a25abdf311ef 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightHandlerFactory.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightHandlerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 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. @@ -15,14 +15,14 @@ */ package org.jetbrains.plugins.groovy.findUsages; -import com.intellij.codeInsight.TargetElementUtilBase; import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerBase; -import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactory; +import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactoryBase; import com.intellij.lang.ASTNode; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; @@ -30,13 +30,9 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini /** * @author Max Medvedev */ -public class GrHighlightHandlerFactory implements HighlightUsagesHandlerFactory { +public class GrHighlightHandlerFactory extends HighlightUsagesHandlerFactoryBase { @Override - public HighlightUsagesHandlerBase createHighlightUsagesHandler(Editor editor, PsiFile file) { - int offset = TargetElementUtilBase.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset()); - final PsiElement target = file.findElementAt(offset); - if (target == null) return null; - + public HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file, @NotNull PsiElement target) { ASTNode node = target.getNode(); if (node == null) return null; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/parameterToEntry/ConvertParameterToMapEntryIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/parameterToEntry/ConvertParameterToMapEntryIntention.java index 318db55df11b..befb360e5885 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/parameterToEntry/ConvertParameterToMapEntryIntention.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/parameterToEntry/ConvertParameterToMapEntryIntention.java @@ -23,6 +23,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; @@ -459,17 +460,33 @@ public class ConvertParameterToMapEntryIntention extends Intention { } }; ReferencesSearch.search(namedElem).forEach(consumer); - if (namedElem instanceof GrField && ((GrField)namedElem).isProperty()) { - final GrAccessorMethod[] getters = ((GrField)namedElem).getGetters(); + boolean isProperty = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { + @Override + public Boolean compute() { + return namedElem instanceof GrField && ((GrField)namedElem).isProperty(); + } + }); + if (isProperty) { + final GrAccessorMethod[] getters = ApplicationManager.getApplication().runReadAction(new Computable<GrAccessorMethod[]>() { + @Override + public GrAccessorMethod[] compute() { + return ((GrField)namedElem).getGetters(); + } + }); for (GrAccessorMethod getter : getters) { MethodReferencesSearch.search(getter).forEach(consumer); } } - for (PsiReference reference : references) { - final PsiElement element = reference.getElement(); - if (element != null) { - occurrences.add(element); - } + for (final PsiReference reference : references) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + final PsiElement element = reference.getElement(); + if (element != null) { + occurrences.add(element); + } + } + }); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyNameSuggestionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyNameSuggestionUtil.java index 6ba946c6798b..b1856c124e0e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyNameSuggestionUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyNameSuggestionUtil.java @@ -128,7 +128,7 @@ public class GroovyNameSuggestionUtil { NameValidator validator, boolean forStaticVariable, Project project) { - if (!JavaPsiFacade.getInstance(project).getNameHelper().isIdentifier(value)) return; + if (!PsiNameHelper.getInstance(project).isIdentifier(value)) return; if (forStaticVariable) { StringBuilder buffer = new StringBuilder(value.length() + 10); char[] chars = new char[value.length()]; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUtil.java index 8c8b156eace4..097d90024daf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUtil.java @@ -17,13 +17,14 @@ package org.jetbrains.plugins.groovy.refactoring.changeSignature; import com.intellij.openapi.project.Project; import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiNameHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil; public class GrChangeSignatureUtil { @NotNull public static String getNameWithQuotesIfNeeded(@NotNull final String originalName, @NotNull final Project project) { - return JavaPsiFacade.getInstance(project).getNameHelper().isIdentifier(originalName) + return PsiNameHelper.getInstance(project).isIdentifier(originalName) ? originalName : GrStringUtil.getLiteralTextByValue(originalName).toString(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantDialog.java index 7658a3e2f211..a6f9673fbe62 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantDialog.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantDialog.java @@ -354,7 +354,7 @@ public class GrIntroduceConstantDialog extends DialogWrapper return; } final String trimmed = targetClassName.trim(); - if (!JavaPsiFacade.getInstance(myContext.getProject()).getNameHelper().isQualifiedName(trimmed)) { + if (!PsiNameHelper.getInstance(myContext.getProject()).isQualifiedName(trimmed)) { setOKActionEnabled(false); return; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantProcessor.java index d3531eac1720..297f3fa7770a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/constant/GrIntroduceConstantProcessor.java @@ -155,13 +155,11 @@ public class GrIntroduceConstantProcessor { return GroovyRefactoringBundle.message("class.language.is.not.groovy"); } - final JavaPsiFacade facade = JavaPsiFacade.getInstance(context.getProject()); - if (fieldName == null || fieldName.isEmpty()) { return RefactoringBundle.message("no.field.name.specified"); } - else if (!facade.getNameHelper().isIdentifier(fieldName)) { + else if (!PsiNameHelper.getInstance(context.getProject()).isIdentifier(fieldName)) { return RefactoringMessageUtil.getIncorrectIdentifierMessage(fieldName); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/DefaultGroovyScriptRunner.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/DefaultGroovyScriptRunner.java index 90e4131f1ef9..7673ff1c334b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/DefaultGroovyScriptRunner.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/DefaultGroovyScriptRunner.java @@ -60,8 +60,6 @@ public class DefaultGroovyScriptRunner extends GroovyScriptRunner { ModulesConfigurator.showDialog(module.getProject(), module.getName(), ClasspathEditor.NAME); return false; } - - return true; } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java index e227a1b34663..790bd2dd5879 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java @@ -42,6 +42,7 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.PsiFile; import com.intellij.testFramework.CompilerTester; import com.intellij.testFramework.IdeaTestUtil; @@ -77,7 +78,7 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC @Override protected void tuneFixture(JavaModuleFixtureBuilder moduleBuilder) throws Exception { - moduleBuilder.setMockJdkLevel(JavaModuleFixtureBuilder.MockJdkLevel.jdk15); + moduleBuilder.setLanguageLevel(LanguageLevel.JDK_1_6); moduleBuilder.addJdk(IdeaTestUtil.getMockJdk17Path().getPath()); super.tuneFixture(moduleBuilder); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.groovy index 9cc93a625c7c..53965939d7e1 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.groovy @@ -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. @@ -25,6 +25,7 @@ import com.intellij.psi.PsiClass import com.intellij.psi.PsiFile import com.intellij.psi.impl.source.PostprocessReformattingAspect import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import com.intellij.util.ui.UIUtil import org.jetbrains.annotations.Nullable import org.jetbrains.plugins.groovy.actions.generate.accessors.GroovyGenerateGetterSetterAction import org.jetbrains.plugins.groovy.actions.generate.constructors.GroovyGenerateConstructorHandler @@ -382,6 +383,7 @@ class GrImportStatementStub { return members } }.invoke(project, myFixture.editor, myFixture.file); + UIUtil.dispatchAllInvocationEvents() PostprocessReformattingAspect.getInstance(project).doPostponedFormatting() } }.execute() diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgChangeProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgChangeProvider.java index daaf6ec33fc5..02e49354f3ab 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgChangeProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgChangeProvider.java @@ -68,6 +68,7 @@ public class HgChangeProvider implements ChangeProvider { public void getChanges(VcsDirtyScope dirtyScope, ChangelistBuilder builder, ProgressIndicator progress, ChangeListManagerGate addGate) throws VcsException { + if (myProject.isDisposed()) return; final Collection<HgChange> changes = new HashSet<HgChange>(); changes.addAll(process(builder, dirtyScope.getRecursivelyDirtyDirectories())); changes.addAll(process(builder, dirtyScope.getDirtyFiles())); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java index 70055cafe1a1..a3ea93d7f0b9 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgOutgoingCommitsProvider.java @@ -16,7 +16,6 @@ package org.zmlx.hg4idea.push; import com.intellij.dvcs.push.*; -import com.intellij.dvcs.repo.Repository; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -27,6 +26,7 @@ import org.zmlx.hg4idea.command.HgOutgoingCommand; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.log.HgBaseLogParser; import org.zmlx.hg4idea.log.HgHistoryUtil; +import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.util.HgChangesetUtil; import org.zmlx.hg4idea.util.HgErrorUtil; import org.zmlx.hg4idea.util.HgVersion; @@ -35,7 +35,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class HgOutgoingCommitsProvider extends OutgoingCommitsProvider { +public class HgOutgoingCommitsProvider extends OutgoingCommitsProvider<HgRepository, HgPushSource, HgTarget> { private static final Logger LOG = Logger.getInstance(HgOutgoingCommitsProvider.class); @@ -43,8 +43,8 @@ public class HgOutgoingCommitsProvider extends OutgoingCommitsProvider { @NotNull @Override - public OutgoingResult getOutgoingCommits(@NotNull final Repository repository, - @NotNull final PushSpec pushSpec, + public OutgoingResult getOutgoingCommits(@NotNull final HgRepository repository, + @NotNull final PushSpec<HgPushSource, HgTarget> pushSpec, boolean initial) { final Project project = repository.getProject(); HgVcs hgvcs = HgVcs.getInstance(project); @@ -52,9 +52,9 @@ public class HgOutgoingCommitsProvider extends OutgoingCommitsProvider { final HgVersion version = hgvcs.getVersion(); String[] templates = HgBaseLogParser.constructFullTemplateArgument(true, version); HgOutgoingCommand hgOutgoingCommand = new HgOutgoingCommand(project); - HgTarget hgTarget = (HgTarget)pushSpec.getTarget(); + HgTarget hgTarget = pushSpec.getTarget(); List<VcsError> errors = new ArrayList<VcsError>(); - if (hgTarget == null || StringUtil.isEmptyOrSpaces(hgTarget.myTarget)) { + if (StringUtil.isEmptyOrSpaces(hgTarget.myTarget)) { errors.add(new VcsError("Hg push path could not be empty.")); return new OutgoingResult(Collections.<VcsFullCommitDetails>emptyList(), errors); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java index 4bfa134a5e26..13f4aaa08f6a 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java @@ -15,12 +15,14 @@ */ package org.zmlx.hg4idea.push; +import com.intellij.dvcs.DvcsUtil; import com.intellij.dvcs.push.*; -import com.intellij.dvcs.repo.Repository; import com.intellij.dvcs.repo.RepositoryManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.AbstractVcs; +import com.intellij.ui.SimpleColoredText; +import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.Function; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; @@ -30,10 +32,11 @@ import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.util.HgUtil; -import java.util.Collection; +import java.util.List; -public class HgPushSupport extends PushSupport<HgRepository> { +public class HgPushSupport extends PushSupport<HgRepository, HgPushSource, HgTarget> { + private final static String ENTER_REMOTE = "Enter Remote"; @NotNull private final Project myProject; @NotNull private final HgVcs myVcs; @@ -50,13 +53,13 @@ public class HgPushSupport extends PushSupport<HgRepository> { @NotNull @Override - public Pusher getPusher() { + public Pusher<HgRepository, HgPushSource, HgTarget> getPusher() { return new HgPusher(); } @NotNull @Override - public OutgoingCommitsProvider getOutgoingCommitsProvider() { + public OutgoingCommitsProvider<HgRepository, HgPushSource, HgTarget> getOutgoingCommitsProvider() { return new HgOutgoingCommitsProvider(); } @@ -69,13 +72,13 @@ public class HgPushSupport extends PushSupport<HgRepository> { @NotNull @Override - public Collection<String> getTargetNames(@NotNull HgRepository repository) { - return ContainerUtil.map(repository.getRepositoryConfig().getPaths(), new Function<String, String>() { + public List<String> getTargetNames(@NotNull HgRepository repository) { + return ContainerUtil.sorted(ContainerUtil.map(repository.getRepositoryConfig().getPaths(), new Function<String, String>() { @Override public String fun(String s) { return HgUtil.removePasswordIfNeeded(s); } - }); + })); } @NotNull @@ -86,6 +89,7 @@ public class HgPushSupport extends PushSupport<HgRepository> { } @Override + @NotNull public HgTarget createTarget(@NotNull HgRepository repository, @NotNull String targetName) { return new HgTarget(targetName); } @@ -103,7 +107,17 @@ public class HgPushSupport extends PushSupport<HgRepository> { @Override @Nullable - public VcsError validate(@NotNull Repository repository, @Nullable String targetToValidate) { - return StringUtil.isEmptyOrSpaces(targetToValidate) ? new VcsError("Please, specify remote push path for repository!") : null; + public VcsError validate(@NotNull HgRepository repository, @Nullable String targetToValidate) { + return StringUtil.isEmptyOrSpaces(targetToValidate) + ? VcsError.createEmptyTargetError(DvcsUtil.getShortRepositoryName(repository)) + : null; + } + + @Override + public SimpleColoredText renderTarget(@Nullable HgTarget target) { + if (target == null || StringUtil.isEmptyOrSpaces(target.getPresentation())) { + return new SimpleColoredText(ENTER_REMOTE, SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES); + } + return new SimpleColoredText(target.getPresentation(), SimpleTextAttributes.SYNTHETIC_ATTRIBUTES); } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java index f019035a373f..e3c91e0103d9 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPusher.java @@ -18,7 +18,6 @@ package org.zmlx.hg4idea.push; import com.intellij.dvcs.push.PushSpec; import com.intellij.dvcs.push.Pusher; import com.intellij.dvcs.push.VcsPushOptionValue; -import com.intellij.dvcs.repo.Repository; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -37,33 +36,30 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class HgPusher extends Pusher { +public class HgPusher extends Pusher<HgRepository, HgPushSource, HgTarget> { private static final Logger LOG = Logger.getInstance(HgPusher.class); private static final String ONE = "one"; private static Pattern PUSH_COMMITS_PATTERN = Pattern.compile(".*(?:added|pushed) (\\d+|" + ONE + ") changeset.*"); // hg push command has definite exit values for some cases: // mercurial returns 0 if push was successful, 1 if nothing to push. see hg push --help - private static int PUSH_SUCCEEDED_EXIT_VALUE = 0; - private static int NOTHING_TO_PUSH_EXIT_VALUE = 1; + static int PUSH_SUCCEEDED_EXIT_VALUE = 0; + static int NOTHING_TO_PUSH_EXIT_VALUE = 1; @Override - public void push(@NotNull Map<Repository, PushSpec> pushSpecs, @Nullable VcsPushOptionValue vcsPushOptionValue, boolean force) { - for (Map.Entry<Repository, PushSpec> entry : pushSpecs.entrySet()) { - Repository repository = entry.getKey(); - HgRepository hgRepository = (HgRepository)repository; - PushSpec hgSpec = entry.getValue(); - HgTarget destination = (HgTarget)hgSpec.getTarget(); - if (destination == null) { - continue; - } - HgPushSource source = (HgPushSource)hgSpec.getSource(); + public void push(@NotNull Map<HgRepository, PushSpec<HgPushSource, HgTarget>> pushSpecs, + @Nullable VcsPushOptionValue vcsPushOptionValue, boolean force) { + for (Map.Entry<HgRepository, PushSpec<HgPushSource, HgTarget>> entry : pushSpecs.entrySet()) { + HgRepository repository = entry.getKey(); + PushSpec<HgPushSource, HgTarget> hgSpec = entry.getValue(); + HgTarget destination = hgSpec.getTarget(); + HgPushSource source = hgSpec.getSource(); Project project = repository.getProject(); final HgPushCommand pushCommand = new HgPushCommand(project, repository.getRoot(), destination.myTarget); pushCommand.setIsNewBranch(true); // set always true, because it just allow mercurial to create a new one if needed pushCommand.setForce(force); String branchName = source.getBranch(); - if (branchName.equals(hgRepository.getCurrentBookmark())) { + if (branchName.equals(repository.getCurrentBookmark())) { if (vcsPushOptionValue == HgVcsPushOptionValue.Current) { pushCommand.setBookmarkName(branchName); } @@ -105,7 +101,7 @@ public class HgPusher extends Pusher { }); } - private static int getNumberOfPushedCommits(@NotNull HgCommandResult result) { + static int getNumberOfPushedCommits(@NotNull HgCommandResult result) { int numberOfCommitsInAllSubrepos = 0; final List<String> outputLines = result.getOutputLines(); for (String outputLine : outputLines) { diff --git a/plugins/hg4idea/testSrc/org/zmlx/hg4idea/push/HgPushParseTest.java b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/push/HgPushParseTest.java new file mode 100644 index 000000000000..5b1774caa2fd --- /dev/null +++ b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/push/HgPushParseTest.java @@ -0,0 +1,75 @@ +/* + * 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.zmlx.hg4idea.push; + +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.zmlx.hg4idea.execution.HgCommandResult; + +import java.io.StringWriter; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; + +@RunWith(Parameterized.class) +public class HgPushParseTest { + + @NotNull private final String myOutput; + private final int myExpected; + + @SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors", "UnusedParameters"}) + public HgPushParseTest(@NotNull String name, @NotNull String output, int expected) { + myOutput = output; + myExpected = expected; + } + + @Parameterized.Parameters(name = "{0}") + public static Collection<Object[]> createData() { + return ContainerUtil.newArrayList(new Object[][]{ + {"DEFAULT_1", "pushing to /Users/user/TTT/AHG\n" + + "searching for changes\n" + + "adding changesets\n" + + "adding manifests\n" + + "adding file changes\n" + + "added 1 changesets with 1 changes to 1 files", 1}, + {"DEFAULT_2", "pushing to /Users/user/TTT/AHG\n" + + "searching for changes\n" + + "adding changesets\n" + + "adding manifests\n" + + "adding file changes\n" + + "added 2 changesets with 3 changes to 1 files", 2}, + {"EXTENSION_KILN_ONE", "hg push http://<my repo>\n" + + "pushing to http://<my repo>\n" + + "searching for changes\n" + + " \"remote: kiln: successfully pushed one changeset", 1}, + {"EXTENSION_KILN_4", "hg push http://<my repo>\n" + + "pushing to http://<my repo>\n" + + "searching for changes\n" + + "remote: kiln: successfully pushed 4 changesets", 4} + }); + } + + @Test + public void testValid() { + StringWriter outWriter = new StringWriter(); + outWriter.write(myOutput); + assertEquals(" Wrong commits number for " + myOutput, myExpected, + HgPusher.getNumberOfPushedCommits(new HgCommandResult(outWriter, new StringWriter(), 0))); + } +} diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/GenerateGetterSetterTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/GenerateGetterSetterTest.java index 8be55aba835a..3c41bf68379a 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/GenerateGetterSetterTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/GenerateGetterSetterTest.java @@ -23,6 +23,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.PsiTestUtil; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -55,6 +56,7 @@ public class GenerateGetterSetterTest extends DaemonAnalyzerTestCase { return members; } }.invoke(getProject(), getEditor(), getFile()); + UIUtil.dispatchAllInvocationEvents(); checkResultByFile("/generateGetterSetter/after" + getTestName(false) + ".java"); } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/codeInsight/JavaFxGetterSetterPrototypeProvider.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/codeInsight/JavaFxGetterSetterPrototypeProvider.java index 8ed3fd8f0e87..8c0ce5742b35 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/codeInsight/JavaFxGetterSetterPrototypeProvider.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/codeInsight/JavaFxGetterSetterPrototypeProvider.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.javaFX.codeInsight; +import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.codeInsight.generation.GetterSetterPrototypeProvider; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -42,7 +43,7 @@ public class JavaFxGetterSetterPrototypeProvider extends GetterSetterPrototypePr public PsiMethod[] generateGetters(PsiField field) { final Project project = field.getProject(); final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - final PsiMethod getter = PropertyUtil.generateGetterPrototype(field); + final PsiMethod getter = GenerateMembersUtil.generateGetterPrototype(field); final PsiType wrappedType = JavaFxPsiUtil.getWrappedPropertyType(field, project, JavaFxCommonClassNames.ourReadOnlyMap); @@ -56,12 +57,12 @@ public class JavaFxGetterSetterPrototypeProvider extends GetterSetterPrototypePr final PsiMethod propertyGetter = PropertyUtil.generateGetterPrototype(field); propertyGetter.setName(JavaCodeStyleManager.getInstance(project).variableNameToPropertyName(field.getName(), VariableKind.FIELD) + "Property"); - return new PsiMethod[] {getter, propertyGetter}; + return new PsiMethod[] {getter, GenerateMembersUtil.annotateOnOverrideImplement(field.getContainingClass(), propertyGetter)}; } @Override public PsiMethod[] generateSetters(PsiField field) { - final PsiMethod setter = PropertyUtil.generateSetterPrototype(field); + final PsiMethod setter = GenerateMembersUtil.generateSetterPrototype(field); final Project project = field.getProject(); final PsiType wrappedType = JavaFxPsiUtil.getWrappedPropertyType(field, project, JavaFxCommonClassNames.ourWritableMap); diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxControllerFieldSearcher.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxControllerFieldSearcher.java index 0f3a1846b4e2..742f84fd3efc 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxControllerFieldSearcher.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxControllerFieldSearcher.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.javaFX.fxml.refs; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -23,6 +24,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.util.Processor; @@ -43,7 +45,12 @@ public class JavaFxControllerFieldSearcher implements QueryExecutor<PsiReference final PsiElement elementToSearch = queryParameters.getElementToSearch(); if (elementToSearch instanceof PsiField) { final PsiField field = (PsiField)elementToSearch; - final PsiClass containingClass = field.getContainingClass(); + final PsiClass containingClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() { + @Override + public PsiClass compute() { + return field.getContainingClass(); + } + }); if (containingClass != null) { final String qualifiedName = ApplicationManager.getApplication().runReadAction(new Computable<String>() { @Override @@ -52,45 +59,40 @@ public class JavaFxControllerFieldSearcher implements QueryExecutor<PsiReference } }); if (qualifiedName != null) { - final List<PsiFile> fxmlWithController = - JavaFxControllerClassIndex.findFxmlWithController(containingClass.getProject(), qualifiedName); - final String fieldName = field.getName(); + Project project = PsiUtilCore.getProjectInReadAction(containingClass); + final List<PsiFile> fxmlWithController = + JavaFxControllerClassIndex.findFxmlWithController(project, qualifiedName); for (final PsiFile file : fxmlWithController) { - final VirtualFile virtualFile = file.getViewProvider().getVirtualFile(); - final SearchScope searchScope = ApplicationManager.getApplication().runReadAction(new Computable<SearchScope>() { + ApplicationManager.getApplication().runReadAction(new Runnable() { @Override - public SearchScope compute() { - return queryParameters.getEffectiveSearchScope(); - } - }); - if (searchScope instanceof LocalSearchScope) { - if (!((LocalSearchScope)searchScope).isInScope(virtualFile)) continue; - } else if (searchScope instanceof GlobalSearchScope) { - if (!((GlobalSearchScope)searchScope).contains(virtualFile)) continue; - } - final Runnable runnable = new Runnable() { public void run() { - file.accept(new XmlRecursiveElementVisitor() { - @Override - public void visitXmlAttributeValue(final XmlAttributeValue value) { - final PsiReference reference = value.getReference(); - if (reference != null) { - final PsiElement resolve = reference.resolve(); - if (resolve instanceof XmlAttributeValue) { - final PsiElement parent = resolve.getParent(); - if (parent instanceof XmlAttribute) { - final XmlAttribute attribute = (XmlAttribute)parent; - if (FxmlConstants.FX_ID.equals(attribute.getName()) && fieldName.equals(attribute.getValue())) { - consumer.process(reference); + final String fieldName = field.getName(); + final VirtualFile virtualFile = file.getViewProvider().getVirtualFile(); + final SearchScope searchScope = queryParameters.getEffectiveSearchScope(); + boolean contains = searchScope instanceof LocalSearchScope ? ((LocalSearchScope)searchScope).isInScope(virtualFile) : + ((GlobalSearchScope)searchScope).contains(virtualFile); + if (contains) { + file.accept(new XmlRecursiveElementVisitor() { + @Override + public void visitXmlAttributeValue(final XmlAttributeValue value) { + final PsiReference reference = value.getReference(); + if (reference != null) { + final PsiElement resolve = reference.resolve(); + if (resolve instanceof XmlAttributeValue) { + final PsiElement parent = resolve.getParent(); + if (parent instanceof XmlAttribute) { + final XmlAttribute attribute = (XmlAttribute)parent; + if (FxmlConstants.FX_ID.equals(attribute.getName()) && fieldName.equals(attribute.getValue())) { + consumer.process(reference); + } } } } } - } - }); + }); + } } - }; - ApplicationManager.getApplication().runReadAction(runnable); + }); } } } diff --git a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenConstants.java b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenConstants.java index 6ba71e747aa1..eb1ba34a325c 100644 --- a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenConstants.java +++ b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenConstants.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. @@ -36,8 +36,6 @@ public class MavenConstants { public static final String SCOPE_COMPILE = "compile"; public static final String SCOPE_PROVIDED = "provided"; - /* @deprecated to remove in IDEA 14 */ - @SuppressWarnings({"UnusedDeclaration", "SpellCheckingInspection"}) public static final String SCOPE_PROVIDEED = SCOPE_PROVIDED; public static final String SCOPE_RUNTIME = "runtime"; public static final String SCOPE_TEST = "test"; public static final String SCOPE_SYSTEM = "system"; diff --git a/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties b/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties index 61b69161c5e3..f8439f059b7e 100644 --- a/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties +++ b/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties @@ -52,5 +52,8 @@ resource.bundle.renamer.dialog.description=Rename resource bundle properties fil resource.bundle.renamer.entity.name=Resource bundle resource.bundle.renamer.option=Rename bound &resource bundle +combine.properties.files.prompt.text=Combine properties files to resource bundle with bundle base name +combine.properties.files.title=Combine to Resource Bundle + inline.property.refactoring=Inline Property inline.property.confirmation=Inline property ''{0}'' with value ''{1}''? diff --git a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java index bb9b9449166f..0867b6b5faa1 100644 --- a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java +++ b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/PropertiesUtil.java @@ -16,16 +16,14 @@ package com.intellij.lang.properties; import com.intellij.lang.properties.psi.PropertiesFile; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.NullableComputable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiFile; import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,8 +36,8 @@ import java.util.regex.Pattern; * @author cdr */ public class PropertiesUtil { - private final static Pattern LOCALE_PATTERN = Pattern.compile("(_[a-zA-Z]{2,8}(_[a-zA-Z]{2}|[0-9]{3})?(_[\\w\\-]+)?)\\.[^_]+$"); - private final static Locale DEFAULT_LOCALE = new Locale("", "", ""); + public final static Pattern LOCALE_PATTERN = Pattern.compile("(_[a-zA-Z]{2,8}(_[a-zA-Z]{2}|[0-9]{3})?(_[\\w\\-]+)?)\\.[^_]+$"); + public static final Set<Character> BASE_NAME_BORDER_CHAR = ContainerUtil.newHashSet('-', '_', '.'); /** @@ -59,12 +57,28 @@ public class PropertiesUtil { } @NotNull - public static String getBaseName(@NotNull PsiFile file) { - return getBaseName(file.getContainingFile().getVirtualFile()); + public static String getDefaultBaseName(final Collection<PropertiesFile> files) { + String commonPrefix = null; + for (PropertiesFile file : files) { + final String baseName = file.getVirtualFile().getNameWithoutExtension(); + if (commonPrefix == null) { + commonPrefix = baseName; + } else { + commonPrefix = StringUtil.commonPrefix(commonPrefix, baseName); + if (commonPrefix.isEmpty()) { + break; + } + } + } + assert commonPrefix != null; + if (!commonPrefix.isEmpty() && BASE_NAME_BORDER_CHAR.contains(commonPrefix.charAt(commonPrefix.length() - 1))) { + commonPrefix = commonPrefix.substring(0, commonPrefix.length() - 1); + } + return commonPrefix; } @NotNull - public static String getBaseName(@NotNull VirtualFile file) { + public static String getDefaultBaseName(@NotNull final VirtualFile file) { final String name = file.getName(); final Matcher matcher = LOCALE_PATTERN.matcher(name); final String baseNameWithExtension; @@ -105,44 +119,21 @@ public class PropertiesUtil { return null; } - @Nullable - public static String getFullName(final PropertiesFile propertiesFile) { - return ApplicationManager.getApplication().runReadAction(new NullableComputable<String>() { - public String compute() { - PsiDirectory directory = propertiesFile.getParent(); - String packageQualifiedName = getPackageQualifiedName(directory); - if (packageQualifiedName == null) { - return null; - } - StringBuilder qName = new StringBuilder(packageQualifiedName); - if (qName.length() > 0) { - qName.append("."); - } - qName.append(getBaseName(propertiesFile.getContainingFile())); - return qName.toString(); - } - }); - } - + /** + * @deprecated use PropertiesUtil.findAllProperties(ResourceBundle resourceBundle, String key) + */ @NotNull - public static Locale getLocale(final VirtualFile propertiesFile) { - String name = propertiesFile.getName(); - final Matcher matcher = LOCALE_PATTERN.matcher(name); - if (matcher.find()) { - String rawLocale = matcher.group(1); - String[] splittedRawLocale = rawLocale.split("_"); - if (splittedRawLocale.length > 1 && splittedRawLocale[1].length() == 2) { - final String language = splittedRawLocale[1]; - final String country = splittedRawLocale.length > 2 ? splittedRawLocale[2] : ""; - final String variant = splittedRawLocale.length > 3 ? splittedRawLocale[3] : ""; - return new Locale(language, country, variant); - } + @Deprecated + public static List<IProperty> findAllProperties(Project project, @NotNull ResourceBundle resourceBundle, String key) { + List<IProperty> result = new SmartList<IProperty>(); + List<PropertiesFile> propertiesFiles = resourceBundle.getPropertiesFiles(); + for (PropertiesFile propertiesFile : propertiesFiles) { + result.addAll(propertiesFile.findPropertiesByKey(key)); } - return DEFAULT_LOCALE; + return result; } - @NotNull - public static List<IProperty> findAllProperties(Project project, @NotNull ResourceBundle resourceBundle, String key) { + public static List<IProperty> findAllProperties(@NotNull ResourceBundle resourceBundle, String key) { List<IProperty> result = new SmartList<IProperty>(); List<PropertiesFile> propertiesFiles = resourceBundle.getPropertiesFiles(); for (PropertiesFile propertiesFile : propertiesFiles) { diff --git a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java index 7ea56269949d..b53cdae358f0 100644 --- a/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java +++ b/plugins/properties/properties-psi-api/src/com/intellij/lang/properties/ResourceBundle.java @@ -26,8 +26,8 @@ import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDirectory; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -38,26 +38,34 @@ public abstract class ResourceBundle { public abstract List<PropertiesFile> getPropertiesFiles(); /** - * @deprecated, use getPropertiesFiles() instead this method + * @deprecated use getPropertiesFiles() instead this method */ @Deprecated @NotNull - public abstract List<PropertiesFile> getPropertiesFiles(final Project project); + public List<PropertiesFile> getPropertiesFiles(final Project project) { + return getPropertiesFiles(); + } @NotNull public abstract PropertiesFile getDefaultPropertiesFile(); /** - * @deprecated, use getDefaultPropertiesFile() instead this method + * @deprecated use getDefaultPropertiesFile() instead this method */ @Deprecated @NotNull - public abstract PropertiesFile getDefaultPropertiesFile(final Project project); + public PropertiesFile getDefaultPropertiesFile(final Project project) { + return getDefaultPropertiesFile(); + } @NotNull public abstract String getBaseName(); - @NotNull + /** + * @return null if resource bundle is not default ( == instance of ResourceBundleImpl) + */ + @Deprecated + @Nullable public abstract VirtualFile getBaseDirectory(); @NotNull diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java index ebe28b38b37e..52b57238d138 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/BundleNameEvaluator.java @@ -37,7 +37,7 @@ public interface BundleNameEvaluator { if (qName.length() > 0) { qName.append("."); } - qName.append(PropertiesUtil.getBaseName(psiFile)); + qName.append(ResourceBundleManager.getInstance(psiFile.getProject()).getBaseName(psiFile)); return qName.toString(); } return null; diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundle.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundle.java new file mode 100644 index 000000000000..d712dc3d8655 --- /dev/null +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundle.java @@ -0,0 +1,109 @@ +/* + * 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.lang.properties; + +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.psi.PsiManager; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class CustomResourceBundle extends ResourceBundle { + private final static Logger LOG = Logger.getInstance(CustomResourceBundle.class); + + private final List<PropertiesFile> myFiles; + private final String myBaseName; + + private CustomResourceBundle(final List<PropertiesFile> files, final @NotNull String baseName) { + LOG.assertTrue(!files.isEmpty()); + myFiles = new ArrayList<PropertiesFile>(files); + Collections.sort(myFiles, new Comparator<PropertiesFile>() { + @Override + public int compare(PropertiesFile f1, PropertiesFile f2) { + return f1.getName().compareTo(f2.getName()); + } + }); + myBaseName = baseName; + } + + public static CustomResourceBundle fromState(final CustomResourceBundleState state, final Project project) { + final PsiManager psiManager = PsiManager.getInstance(project); + final List<PropertiesFile> files = + ContainerUtil.map(state.getFiles(VirtualFileManager.getInstance()), new Function<VirtualFile, PropertiesFile>() { + @Override + public PropertiesFile fun(VirtualFile virtualFile) { + return PropertiesImplUtil.getPropertiesFile(psiManager.findFile(virtualFile)); + } + }); + return files.size() < 2 ? null : new CustomResourceBundle(files, state.getBaseName()); + } + + @NotNull + @Override + public List<PropertiesFile> getPropertiesFiles() { + return myFiles; + } + + @NotNull + @Override + public PropertiesFile getDefaultPropertiesFile() { + return ContainerUtil.getFirstItem(myFiles); + } + + @NotNull + @Override + public String getBaseName() { + return myBaseName; + } + + @Nullable + @Override + public VirtualFile getBaseDirectory() { + return null; + } + + @NotNull + @Override + public Project getProject() { + return getDefaultPropertiesFile().getProject(); + } + + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final CustomResourceBundle resourceBundle = (CustomResourceBundle)o; + return resourceBundle.getPropertiesFiles().equals(resourceBundle.getPropertiesFiles()) && + resourceBundle.getBaseName().equals(getBaseName()); + } + + public int hashCode() { + return myFiles.hashCode() * 31 + myBaseName.hashCode(); + } +} diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundleState.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundleState.java new file mode 100644 index 000000000000..9be149d6a4db --- /dev/null +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/CustomResourceBundleState.java @@ -0,0 +1,93 @@ +/* + * 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.lang.properties; + +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashSet; +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Property; +import com.intellij.util.xmlb.annotations.Tag; +import com.intellij.util.xmlb.annotations.Transient; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * @author Dmitry Batkovich + */ +@Tag("custom-resource-bundle") +public class CustomResourceBundleState { + + @Property(surroundWithTag = false) + @AbstractCollection(surroundWithTag = false, elementTag = "file", elementValueAttribute = "value") + public Set<String> myFileUrls = new HashSet<String>(); + + @Tag("base-name") + public String myBaseName; + + @Transient + @NotNull + public String getBaseName() { + return myBaseName; + } + + public Set<String> getFileUrls() { + return myFileUrls; + } + + public List<VirtualFile> getFiles(@NotNull final VirtualFileManager manager) { + return ContainerUtil.mapNotNull(getFileUrls(), new Function<String, VirtualFile>() { + @Override + public VirtualFile fun(String url) { + return manager.findFileByUrl(url); + } + }); + } + + @Nullable + public CustomResourceBundleState removeNonExistentFiles(final VirtualFileManager virtualFileManager) { + final List<String> existentFiles = ContainerUtil.filter(myFileUrls, new Condition<String>() { + @Override + public boolean value(String url) { + return virtualFileManager.findFileByUrl(url) != null; + } + }); + if (existentFiles.isEmpty()) { + return null; + } + final CustomResourceBundleState customResourceBundleState = new CustomResourceBundleState(); + customResourceBundleState.myFileUrls.addAll(existentFiles); + customResourceBundleState.myBaseName = myBaseName; + return customResourceBundleState; + } + + public CustomResourceBundleState addAll(final Collection<String> urls) { + myFileUrls.addAll(urls); + return this; + } + + public CustomResourceBundleState setBaseName(String baseName) { + myBaseName = baseName; + return this; + } +} diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java index f667b1a93da0..15e73791f8ea 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.lang.properties; +import com.intellij.lang.HtmlScriptContentProvider; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.lang.properties.psi.PropertyKeyIndex; import com.intellij.lang.properties.xml.XmlPropertiesFileImpl; @@ -48,7 +49,23 @@ public class PropertiesImplUtil extends PropertiesUtil { if (!containingFile.isValid()) { return EmptyResourceBundle.getInstance(); } - final String baseName = getBaseName(containingFile); + final ResourceBundleManager manager = ResourceBundleManager.getInstance(representative.getProject()); + final CustomResourceBundle customResourceBundle = + manager.getCustomResourceBundle(representative); + if (customResourceBundle != null) { + return customResourceBundle; + } + + final VirtualFile virtualFile = representative.getVirtualFile(); + if (virtualFile == null) { + return EmptyResourceBundle.getInstance(); + } + if (manager.isDefaultDissociated(virtualFile)) { + return new ResourceBundleImpl(representative); + } + + + final String baseName = manager.getBaseName(containingFile); final PsiDirectory directory = ApplicationManager.getApplication().runReadAction(new Computable<PsiDirectory>() { @Nullable public PsiDirectory compute() { @@ -61,14 +78,9 @@ public class PropertiesImplUtil extends PropertiesUtil { @Nullable private static ResourceBundle getResourceBundle(@NotNull final String baseName, @NotNull final PsiDirectory baseDirectory) { PropertiesFile defaultPropertiesFile = null; - final PsiFile[] files = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile[]>() { - @Override - public PsiFile[] compute() { - return baseDirectory.getFiles(); - } - }); - for (final PsiFile psiFile : files) { - if (baseName.equals(getBaseName(psiFile))) { + final ResourceBundleManager bundleBaseNameManager = ResourceBundleManager.getInstance(baseDirectory.getProject()); + for (final PsiFile psiFile : baseDirectory.getFiles()) { + if (baseName.equals(bundleBaseNameManager.getBaseName(psiFile))) { final PropertiesFile propertiesFile = getPropertiesFile(psiFile); if (propertiesFile != null) { if (defaultPropertiesFile == null || defaultPropertiesFile.getName().compareTo(propertiesFile.getName()) > 0) { diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java index ca5c8aa39a36..bad9957f7523 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java @@ -27,6 +27,7 @@ import com.intellij.psi.PsiFile; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; +import java.util.Collections; import java.util.List; public class ResourceBundleImpl extends ResourceBundle { @@ -39,12 +40,15 @@ public class ResourceBundleImpl extends ResourceBundle { @NotNull @Override public List<PropertiesFile> getPropertiesFiles() { + if (ResourceBundleManager.getInstance(getProject()).isDefaultDissociated(myDefaultPropertiesFile.getVirtualFile())) { + return Collections.singletonList(myDefaultPropertiesFile); + } PsiFile[] children = myDefaultPropertiesFile.getParent().getFiles(); final String baseName = getBaseName(); List<PropertiesFile> result = new SmartList<PropertiesFile>(); for (PsiFile file : children) { if (!file.isValid() || file.getVirtualFile().getExtension() == null) continue; - if (Comparing.strEqual(PropertiesUtil.getBaseName(file), baseName)) { + if (Comparing.strEqual(PropertiesUtil.getDefaultBaseName(file.getVirtualFile()), baseName)) { PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(file); if (propertiesFile != null) { result.add(propertiesFile); @@ -56,26 +60,14 @@ public class ResourceBundleImpl extends ResourceBundle { @NotNull @Override - public List<PropertiesFile> getPropertiesFiles(final Project project) { - return getPropertiesFiles(); - } - - @NotNull - @Override public PropertiesFile getDefaultPropertiesFile() { return myDefaultPropertiesFile; } @NotNull @Override - public PropertiesFile getDefaultPropertiesFile(final Project project) { - return getDefaultPropertiesFile(); - } - - @NotNull - @Override public String getBaseName() { - return PropertiesUtil.getBaseName(myDefaultPropertiesFile.getContainingFile()); + return ResourceBundleManager.getInstance(getProject()).getBaseName(myDefaultPropertiesFile.getContainingFile()); } @NotNull diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java new file mode 100644 index 000000000000..a01c123f8763 --- /dev/null +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java @@ -0,0 +1,256 @@ +/* + * 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.lang.properties; + +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.*; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.NullableComputable; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Locale; +import java.util.regex.Matcher; + +/** + * @author Dmitry Batkovich + */ +@State( + name = "ResourceBundleManager", + storages = { + @Storage(file = StoragePathMacros.PROJECT_FILE), + @Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/resourceBundles.xml", scheme = StorageScheme.DIRECTORY_BASED) + }) +public class ResourceBundleManager implements PersistentStateComponent<ResourceBundleManagerState> { + private final static Logger LOG = Logger.getInstance(ResourceBundleManager.class); + private final static Locale DEFAULT_LOCALE = new Locale("", "", ""); + + private ResourceBundleManagerState myState = new ResourceBundleManagerState(); + + public ResourceBundleManager(final PsiManager manager) { + manager.addPsiTreeChangeListener(new PsiTreeChangeAdapter() { + @Override + public void childMoved(@NotNull PsiTreeChangeEvent event) { + final PsiElement child = event.getChild(); + if (!(child instanceof PsiFile)) { + return; + } + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile((PsiFile)child); + if (propertiesFile == null) { + return; + } + final String oldParentUrl = getUrl(event.getOldParent()); + final String newParentUrl = getUrl(event.getNewParent()); + if (oldParentUrl == null || newParentUrl == null) { + return; + } + final String newUrl = propertiesFile.getVirtualFile().getUrl(); + final String oldUrl = oldParentUrl + newUrl.substring(newParentUrl.length()); + if (myState.getDissociatedFiles().remove(oldUrl)) { + myState.getDissociatedFiles().add(newUrl); + } + + for (CustomResourceBundleState customResourceBundleState : myState.getCustomResourceBundles()) { + if (customResourceBundleState.getFileUrls().remove(oldUrl)) { + customResourceBundleState.getFileUrls().add(newUrl); + break; + } + } + } + + @Nullable + private String getUrl(PsiElement element) { + return !(element instanceof PsiDirectory) ? null : ((PsiDirectory)element).getVirtualFile().getUrl(); + } + + @Override + public void childReplaced(@NotNull PsiTreeChangeEvent event) { + super.childReplaced(event); + } + + @Override + public void beforeChildMovement(@NotNull PsiTreeChangeEvent event) { + super.beforeChildMovement(event); + } + + @Override + public void propertyChanged(@NotNull PsiTreeChangeEvent event) { + super.propertyChanged(event); + } + + @Override + public void childRemoved(@NotNull PsiTreeChangeEvent event) { + final PsiElement child = event.getChild(); + if (!(child instanceof PsiFile)) { + return; + } + PropertiesFile file = PropertiesImplUtil.getPropertiesFile((PsiFile)child); + if (file == null) { + return; + } + final VirtualFile virtualFile = file.getVirtualFile(); + final String url = virtualFile.getUrl(); + myState.getDissociatedFiles().remove(url); + for (CustomResourceBundleState customResourceBundleState : myState.getCustomResourceBundles()) { + if (customResourceBundleState.getFileUrls().remove(url)) { + if (customResourceBundleState.getFileUrls().size() < 2) { + myState.getCustomResourceBundles().remove(customResourceBundleState); + } + break; + } + } + } + }); + } + + public static ResourceBundleManager getInstance(final Project project) { + return ServiceManager.getService(project, ResourceBundleManager.class); + } + + @Nullable + public String getFullName(final @NotNull PropertiesFile propertiesFile) { + return ApplicationManager.getApplication().runReadAction(new NullableComputable<String>() { + public String compute() { + final PsiDirectory directory = propertiesFile.getParent(); + final String packageQualifiedName = PropertiesUtil.getPackageQualifiedName(directory); + if (packageQualifiedName == null) { + return null; + } + final StringBuilder qName = new StringBuilder(packageQualifiedName); + if (qName.length() > 0) { + qName.append("."); + } + qName.append(getBaseName(propertiesFile.getContainingFile())); + return qName.toString(); + } + }); + } + + @NotNull + public Locale getLocale(final @NotNull VirtualFile propertiesFile) { + final String customResourceBundleName = getCustomResourceBundleName(propertiesFile); + + String name = propertiesFile.getName(); + if (customResourceBundleName != null) { + name = name.substring(customResourceBundleName.length()); + } + + final Matcher matcher = PropertiesUtil.LOCALE_PATTERN.matcher(name); + if (matcher.find()) { + final String rawLocale = matcher.group(1); + final String[] splittedRawLocale = rawLocale.split("_"); + if (splittedRawLocale.length > 1 && splittedRawLocale[1].length() >= 2) { + final String language = splittedRawLocale[1]; + final String country = splittedRawLocale.length > 2 ? splittedRawLocale[2] : ""; + final String variant = splittedRawLocale.length > 3 ? splittedRawLocale[3] : ""; + return new Locale(language, country, variant); + } + } + return DEFAULT_LOCALE; + } + + @NotNull + public String getBaseName(@NotNull final PsiFile file) { + return getBaseName(file.getVirtualFile()); + } + + @NotNull + private String getBaseName(@NotNull final VirtualFile file) { + final CustomResourceBundleState customResourceBundle = getCustomResourceBundleState(file); + if (customResourceBundle != null) { + return customResourceBundle.getBaseName(); + } + if (isDefaultDissociated(file)) { + return file.getNameWithoutExtension(); + } + return PropertiesUtil.getDefaultBaseName(file); + } + + + public void dissociateResourceBundle(final @NotNull ResourceBundle resourceBundle) { + if (resourceBundle instanceof CustomResourceBundle) { + final CustomResourceBundleState state = + getCustomResourceBundleState(resourceBundle.getDefaultPropertiesFile().getVirtualFile()); + LOG.assertTrue(state != null); + myState.getCustomResourceBundles().remove(state); + } else { + for (final PropertiesFile propertiesFile : resourceBundle.getPropertiesFiles()) { + final VirtualFile file = propertiesFile.getContainingFile().getVirtualFile(); + myState.getDissociatedFiles().add(file.getUrl()); + } + } + } + + public void combineToResourceBundle(final @NotNull List<PropertiesFile> propertiesFiles, final String baseName) { + myState.getCustomResourceBundles() + .add(new CustomResourceBundleState().addAll(ContainerUtil.map(propertiesFiles, new Function<PropertiesFile, String>() { + @Override + public String fun(PropertiesFile file) { + return file.getVirtualFile().getUrl(); + } + })).setBaseName(baseName)); + } + + @Nullable + public CustomResourceBundle getCustomResourceBundle(final @NotNull PropertiesFile file) { + final VirtualFile virtualFile = file.getVirtualFile(); + if (virtualFile == null) { + return null; + } + final CustomResourceBundleState state = getCustomResourceBundleState(virtualFile); + return state == null ? null : CustomResourceBundle.fromState(state, file.getProject()); + } + + public boolean isDefaultDissociated(final @NotNull VirtualFile virtualFile) { + final String url = virtualFile.getUrl(); + return myState.getDissociatedFiles().contains(url) || getCustomResourceBundleState(virtualFile) != null; + } + + @Nullable + private String getCustomResourceBundleName(final @NotNull VirtualFile virtualFile) { + final CustomResourceBundleState customResourceBundle = getCustomResourceBundleState(virtualFile); + return customResourceBundle == null ? null : customResourceBundle.getBaseName(); + } + + @Nullable + private CustomResourceBundleState getCustomResourceBundleState(final @NotNull VirtualFile virtualFile) { + final String url = virtualFile.getUrl(); + for (CustomResourceBundleState customResourceBundleState : myState.getCustomResourceBundles()) { + if (customResourceBundleState.getFileUrls().contains(url)) { + return customResourceBundleState; + } + } + return null; + } + + @Nullable + @Override + public ResourceBundleManagerState getState() { + return myState.isEmpty() ? null : myState; + } + + @Override + public void loadState(ResourceBundleManagerState state) { + myState = state.removeNonExistentFiles(); + } +} diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManagerState.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManagerState.java new file mode 100644 index 000000000000..c4d1e5c5cb2d --- /dev/null +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManagerState.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 com.intellij.lang.properties; + +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.util.containers.HashSet; +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Property; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * @author Dmitry Batkovich + */ +public class ResourceBundleManagerState { + + @Property(surroundWithTag = false) + @AbstractCollection(elementValueAttribute = "url", elementTag = "file", surroundWithTag = false) + public Set<String> myDissociatedFiles = new HashSet<String>(); + + @Property(surroundWithTag = false) + @AbstractCollection(elementTag = "custom-rb", surroundWithTag = false) + public List<CustomResourceBundleState> myCustomResourceBundles = new ArrayList<CustomResourceBundleState>(); + + public Set<String> getDissociatedFiles() { + return myDissociatedFiles; + } + + public List<CustomResourceBundleState> getCustomResourceBundles() { + return myCustomResourceBundles; + } + + public boolean isEmpty() { + return myCustomResourceBundles.isEmpty() && myDissociatedFiles.isEmpty(); + } + + public ResourceBundleManagerState removeNonExistentFiles() { + final ResourceBundleManagerState newState = new ResourceBundleManagerState(); + + final VirtualFileManager virtualFileManager = VirtualFileManager.getInstance(); + + for (final String dissociatedFileUrl : myDissociatedFiles) { + if (virtualFileManager.findFileByUrl(dissociatedFileUrl) != null) { + newState.myDissociatedFiles.add(dissociatedFileUrl); + } + } + + for (CustomResourceBundleState customResourceBundle : myCustomResourceBundles) { + final CustomResourceBundleState updatedCustomResourceBundle = customResourceBundle.removeNonExistentFiles(virtualFileManager); + if (updatedCustomResourceBundle != null) { + newState.myCustomResourceBundles.add(updatedCustomResourceBundle); + } + } + + return newState; + } +} diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java index 724a794ca3bb..14cb1cb940c4 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/editor/ResourceBundlePropertyStructureViewElement.java @@ -20,11 +20,8 @@ package com.intellij.lang.properties.editor; import com.intellij.ide.structureView.StructureViewTreeElement; -import com.intellij.lang.properties.IProperty; -import com.intellij.lang.properties.PropertiesHighlighter; -import com.intellij.lang.properties.PropertiesUtil; +import com.intellij.lang.properties.*; import com.intellij.lang.properties.ResourceBundle; -import com.intellij.lang.properties.psi.Property; import com.intellij.navigation.ColoredItemPresentation; import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.editor.colors.EditorColorsManager; @@ -62,7 +59,7 @@ public class ResourceBundlePropertyStructureViewElement implements StructureView @Override public PsiElement[] getPsiElements() { - return new PsiElement[] {getProperty().getPsiElement()}; + return new PsiElement[] {getValue()}; } public void setPresentableName(final String presentableName) { @@ -70,8 +67,8 @@ public class ResourceBundlePropertyStructureViewElement implements StructureView } @Override - public Property getValue() { - return (Property)myProperty.getPsiElement(); + public PsiElement getValue() { + return myProperty.getPsiElement(); } @Override diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java index 759ce6cb46fb..99d06e8da06b 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/psi/impl/PropertiesFileImpl.java @@ -20,6 +20,7 @@ import com.intellij.lang.ASTFactory; import com.intellij.lang.ASTNode; import com.intellij.lang.properties.*; import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.ResourceBundleManager; import com.intellij.lang.properties.parsing.PropertiesElementTypes; import com.intellij.lang.properties.psi.PropertiesElementFactory; import com.intellij.lang.properties.psi.PropertiesFile; @@ -120,7 +121,7 @@ public class PropertiesFileImpl extends PsiFileBase implements PropertiesFile { @Override @NotNull public Locale getLocale() { - return PropertiesUtil.getLocale(getVirtualFile()); + return ResourceBundleManager.getInstance(getProject()).getLocale(getVirtualFile()); } @Override diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java index 4b8953f47e9c..6c2453b94144 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/xml/XmlPropertiesFileImpl.java @@ -17,8 +17,8 @@ package com.intellij.lang.properties.xml; import com.intellij.lang.properties.IProperty; import com.intellij.lang.properties.PropertiesImplUtil; -import com.intellij.lang.properties.PropertiesUtil; import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.ResourceBundleManager; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.lang.properties.psi.Property; import com.intellij.openapi.project.Project; @@ -107,7 +107,7 @@ public class XmlPropertiesFileImpl extends XmlPropertiesFile { @NotNull @Override public Locale getLocale() { - return PropertiesUtil.getLocale(getVirtualFile()); + return ResourceBundleManager.getInstance(getProject()).getLocale(getVirtualFile()); } @NotNull diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/properties/PropertiesCoreEnvironment.java b/plugins/properties/properties-psi-impl/src/com/intellij/properties/PropertiesCoreEnvironment.java index f946e41c26ae..52d4d5934b40 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/properties/PropertiesCoreEnvironment.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/properties/PropertiesCoreEnvironment.java @@ -25,6 +25,7 @@ import com.intellij.lang.LanguageParserDefinitions; import com.intellij.lang.findUsages.LanguageFindUsages; import com.intellij.lang.folding.LanguageFolding; import com.intellij.lang.properties.*; +import com.intellij.lang.properties.ResourceBundleManager; import com.intellij.lang.properties.editor.PropertiesFoldingBuilder; import com.intellij.lang.properties.findUsages.PropertiesFindUsagesProvider; import com.intellij.lang.properties.parsing.PropertiesElementTypes; @@ -87,6 +88,7 @@ public class PropertiesCoreEnvironment { public ProjectEnvironment(CoreProjectEnvironment projectEnvironment) { projectEnvironment.getProject().registerService(PropertiesReferenceManager.class); projectEnvironment.getProject().registerService(PropertiesSeparatorManager.class); + projectEnvironment.getProject().registerService(ResourceBundleManager.class); } } } diff --git a/plugins/properties/src/META-INF/plugin.xml b/plugins/properties/src/META-INF/plugin.xml index 513678dcbf72..672add1a002d 100644 --- a/plugins/properties/src/META-INF/plugin.xml +++ b/plugins/properties/src/META-INF/plugin.xml @@ -34,6 +34,7 @@ implementationClass="com.intellij.lang.properties.PropertyManipulator"/> <projectService serviceInterface="com.intellij.lang.properties.structureView.PropertiesSeparatorManager" serviceImplementation="com.intellij.lang.properties.structureView.PropertiesSeparatorManager"/> + <projectService serviceImplementation="com.intellij.lang.properties.ResourceBundleManager"/> <codeInsight.wordCompletionFilter language="Properties" implementationClass="com.intellij.lang.properties.PropertiesWordCompletionFilter"/> <lang.psiStructureViewFactory language="Properties" @@ -98,6 +99,12 @@ </project-components> <actions> + <action id="DissociateResourceBundleAction" class="com.intellij.lang.properties.customizeActions.DissociateResourceBundleAction"> + <add-to-group group-id="ProjectViewPopupMenu"/> + </action> + <action id="CombinePropertiesFilesAction" class="com.intellij.lang.properties.customizeActions.CombinePropertiesFilesAction"> + <add-to-group group-id="ProjectViewPopupMenu"/> + </action> <action id="ChooseNextSubsequentPropertyValueEditorAction" class="com.intellij.lang.properties.editor.ChooseSubsequentPropertyValueEditorAction$Next" text="Choose Next Property Value Editor" diff --git a/plugins/properties/src/com/intellij/lang/properties/PropertiesFilesManager.java b/plugins/properties/src/com/intellij/lang/properties/PropertiesFilesManager.java index 60d337681a31..5477c137021e 100644 --- a/plugins/properties/src/com/intellij/lang/properties/PropertiesFilesManager.java +++ b/plugins/properties/src/com/intellij/lang/properties/PropertiesFilesManager.java @@ -20,7 +20,7 @@ import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingManager; import com.intellij.psi.search.FileTypeIndex; @@ -44,20 +44,24 @@ public class PropertiesFilesManager extends AbstractProjectComponent { super(project); } + @Override public void projectOpened() { final PropertyChangeListener myListener = new PropertyChangeListener() { + @Override public void propertyChange(final PropertyChangeEvent evt) { String propertyName = evt.getPropertyName(); if (EncodingManager.PROP_NATIVE2ASCII_SWITCH.equals(propertyName) || EncodingManager.PROP_PROPERTIES_FILES_ENCODING.equals(propertyName) ) { DumbService.getInstance(myProject).smartInvokeLater(new Runnable(){ + @Override public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable(){ + @Override public void run() { Collection<VirtualFile> filesToRefresh = FileBasedIndex.getInstance() .getContainingFiles(FileTypeIndex.NAME, PropertiesFileType.INSTANCE, GlobalSearchScope.allScope(myProject)); - VirtualFile[] virtualFiles = VfsUtil.toVirtualFileArray(filesToRefresh); + VirtualFile[] virtualFiles = VfsUtilCore.toVirtualFileArray(filesToRefresh); FileDocumentManager.getInstance().saveAllDocuments(); //force to re-detect encoding @@ -75,6 +79,7 @@ public class PropertiesFilesManager extends AbstractProjectComponent { EncodingManager.getInstance().addPropertyChangeListener(myListener,myProject); } + @Override @NotNull public String getComponentName() { return "PropertiesFileManager"; diff --git a/plugins/properties/src/com/intellij/lang/properties/ResourceBundleReference.java b/plugins/properties/src/com/intellij/lang/properties/ResourceBundleReference.java index 5f708c3eda61..14ac858d9917 100644 --- a/plugins/properties/src/com/intellij/lang/properties/ResourceBundleReference.java +++ b/plugins/properties/src/com/intellij/lang/properties/ResourceBundleReference.java @@ -97,14 +97,14 @@ public class ResourceBundleReference extends PsiReferenceBase<PsiElement> implem if (!(element instanceof PropertiesFile)) { throw new IncorrectOperationException(); } - final String name = PropertiesUtil.getFullName((PropertiesFile)element); + final String name = ResourceBundleManager.getInstance(element.getProject()).getFullName((PropertiesFile)element); return super.handleElementRename(name); } public boolean isReferenceTo(PsiElement element) { if (element instanceof PropertiesFile) { - final String name = PropertiesUtil.getFullName((PropertiesFile)element); + final String name = ResourceBundleManager.getInstance(element.getProject()).getFullName((PropertiesFile)element); if (name != null && name.equals(myBundleName)) { return true; } diff --git a/plugins/properties/src/com/intellij/lang/properties/customizeActions/CombinePropertiesFilesAction.java b/plugins/properties/src/com/intellij/lang/properties/customizeActions/CombinePropertiesFilesAction.java new file mode 100644 index 000000000000..b90e74a2c767 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/customizeActions/CombinePropertiesFilesAction.java @@ -0,0 +1,155 @@ +/* + * 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.lang.properties.customizeActions; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.projectView.ProjectView; +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.PropertiesImplUtil; +import com.intellij.lang.properties.PropertiesUtil; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.ResourceBundleManager; +import com.intellij.lang.properties.editor.ResourceBundleAsVirtualFile; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.InputValidatorEx; +import com.intellij.openapi.ui.Messages; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class CombinePropertiesFilesAction extends AnAction { + + public CombinePropertiesFilesAction() { + super(PropertiesBundle.message("combine.properties.files.title"), null, AllIcons.FileTypes.Properties); + } + + @Override + public void actionPerformed(final AnActionEvent e) { + final List<PropertiesFile> propertiesFiles = getPropertiesFiles(e); + final String newBaseName = Messages.showInputDialog(propertiesFiles.get(0).getProject(), + PropertiesBundle.message("combine.properties.files.prompt.text"), + PropertiesBundle.message("combine.properties.files.title"), + Messages.getQuestionIcon(), + PropertiesUtil.getDefaultBaseName(propertiesFiles), + new MyInputValidator(propertiesFiles)); + if (newBaseName != null) { + final Project project = propertiesFiles.get(0).getProject(); + ResourceBundleManager.getInstance(project).combineToResourceBundle(propertiesFiles, newBaseName); + final ResourceBundle resourceBundle = propertiesFiles.get(0).getResourceBundle(); + FileEditorManager.getInstance(project).openFile(new ResourceBundleAsVirtualFile(resourceBundle), true); + ProjectView.getInstance(project).refresh(); + } + } + + @Override + public void update(final AnActionEvent e) { + final List<PropertiesFile> propertiesFiles = getPropertiesFiles(e); + boolean isAvailable = propertiesFiles != null && propertiesFiles.size() > 1; + if (isAvailable) { + for (PropertiesFile propertiesFile : propertiesFiles) { + if (propertiesFile.getResourceBundle().getPropertiesFiles().size() != 1) { + isAvailable = false; + break; + } + } + } + e.getPresentation().setVisible(isAvailable); + } + + @Nullable + private static List<PropertiesFile> getPropertiesFiles(AnActionEvent e) { + final PsiElement[] psiElements = e.getData(LangDataKeys.PSI_ELEMENT_ARRAY); + if (psiElements == null || psiElements.length == 0) { + return null; + } + final List<PropertiesFile> files = new ArrayList<PropertiesFile>(psiElements.length); + for (PsiElement psiElement : psiElements) { + if (!(psiElement instanceof PsiFile)) { + return null; + } + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile((PsiFile)psiElement); + if (propertiesFile == null) { + return null; + } + files.add(propertiesFile); + } + return files; + } + + @Override + public boolean isDumbAware() { + return true; + } + + private static class MyInputValidator implements InputValidatorEx { + private final List<PropertiesFile> myPropertiesFiles; + + private MyInputValidator(final List<PropertiesFile> propertiesFiles) { + myPropertiesFiles = propertiesFiles; + } + + @Override + public boolean checkInput(final String newBaseName) { + return !newBaseName.isEmpty() && checkBaseName(newBaseName) == null; + } + + @Override + public boolean canClose(final String newBaseName) { + return true; + } + + @Nullable + @Override + public String getErrorText(String inputString) { + return checkInput(inputString) ? null : String.format("Base name must be valid for file \'%s\'", checkBaseName(inputString).getFailedFile()); + } + + @Nullable + private BaseNameError checkBaseName(final String baseNameCandidate) { + for (PropertiesFile propertiesFile : myPropertiesFiles) { + final String name = propertiesFile.getVirtualFile().getName(); + if (!name.startsWith(baseNameCandidate) || !PropertiesUtil.BASE_NAME_BORDER_CHAR.contains(name.charAt(baseNameCandidate.length()))) { + return new BaseNameError(name); + } + } + return null; + } + + private static class BaseNameError { + + private final String myFailedFile; + + private BaseNameError(String failedFile) { + myFailedFile = failedFile; + } + + public String getFailedFile() { + return myFailedFile; + } + } + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java b/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java new file mode 100644 index 000000000000..10041448d97c --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/customizeActions/DissociateResourceBundleAction.java @@ -0,0 +1,80 @@ +/* + * 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.lang.properties.customizeActions; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.projectView.ProjectView; +import com.intellij.lang.properties.PropertiesImplUtil; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.ResourceBundleManager; +import com.intellij.lang.properties.editor.ResourceBundleAsVirtualFile; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.Nullable; + +/** + * @author Dmitry Batkovich + */ +public class DissociateResourceBundleAction extends AnAction { + private static final String PRESENTATION_TEXT_TEMPLATE = "Dissociate Resource Bundle '%s'"; + + public DissociateResourceBundleAction() { + super(null, null, AllIcons.FileTypes.Properties); + } + + @Override + public void actionPerformed(final AnActionEvent e) { + final ResourceBundle resourceBundle = extractResourceBundle(e); + assert resourceBundle != null; + final Project project = resourceBundle.getProject(); + final FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); + fileEditorManager.closeFile(new ResourceBundleAsVirtualFile(resourceBundle)); + for (final PropertiesFile propertiesFile : resourceBundle.getPropertiesFiles()) { + fileEditorManager.closeFile(propertiesFile.getVirtualFile()); + } + ResourceBundleManager.getInstance(e.getProject()).dissociateResourceBundle(resourceBundle); + ProjectView.getInstance(project).refresh(); + } + + @Override + public void update(final AnActionEvent e) { + final ResourceBundle resourceBundle = extractResourceBundle(e); + if (resourceBundle != null) { + e.getPresentation().setText(String.format(PRESENTATION_TEXT_TEMPLATE, resourceBundle.getBaseName()), false); + e.getPresentation().setVisible(true); + } else { + e.getPresentation().setVisible(false); + } + } + + @Nullable + private static ResourceBundle extractResourceBundle(final AnActionEvent event) { + final ResourceBundle[] data = event.getData(ResourceBundle.ARRAY_DATA_KEY); + if (data != null && data.length == 1 && data[0].getPropertiesFiles().size() > 1) { + return data[0]; + } + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(event.getData(PlatformDataKeys.PSI_FILE)); + if (propertiesFile == null) { + return null; + } + final ResourceBundle resourceBundle = propertiesFile.getResourceBundle(); + return resourceBundle.getPropertiesFiles().size() > 1 ? resourceBundle : null; + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java index 36915e7e6962..bae39bd9f2d0 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java @@ -23,14 +23,10 @@ import com.intellij.ide.presentation.Presentation; import com.intellij.lang.properties.PropertiesImplUtil; import com.intellij.lang.properties.PropertiesUtil; import com.intellij.lang.properties.ResourceBundle; -import com.intellij.lang.properties.psi.PropertiesFile; -import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileSystem; -import com.intellij.psi.PsiManager; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.io.InputStream; @@ -38,25 +34,15 @@ import java.io.OutputStream; @Presentation(icon = "AllIcons.Nodes.ResourceBundle") public class ResourceBundleAsVirtualFile extends VirtualFile { - private final VirtualFile myBasePropertiesFile; + private final ResourceBundle myResourceBundle; - private ResourceBundleAsVirtualFile(@NotNull final VirtualFile basePropertiesFile) { - myBasePropertiesFile = basePropertiesFile; + public ResourceBundleAsVirtualFile(@NotNull final ResourceBundle resourceBundle) { + myResourceBundle = resourceBundle; } @NotNull - public static ResourceBundleAsVirtualFile fromResourceBundle(final @NotNull ResourceBundle resourceBundle) { - return new ResourceBundleAsVirtualFile(resourceBundle.getDefaultPropertiesFile().getVirtualFile()); - } - - @Nullable - public ResourceBundle getResourceBundle(final Project project) { - final PsiManager psiManager = PsiManager.getInstance(project); - final PropertiesFile file = PropertiesImplUtil.getPropertiesFile(psiManager.findFile(myBasePropertiesFile)); - if (file == null) { - return null; - } - return PropertiesImplUtil.getResourceBundle(file); + public ResourceBundle getResourceBundle() { + return myResourceBundle; } @Override @@ -74,7 +60,7 @@ public class ResourceBundleAsVirtualFile extends VirtualFile { @Override @NotNull public String getName() { - return PropertiesUtil.getBaseName(myBasePropertiesFile); + return myResourceBundle.getBaseName(); } public boolean equals(final Object o) { @@ -83,13 +69,13 @@ public class ResourceBundleAsVirtualFile extends VirtualFile { final ResourceBundleAsVirtualFile resourceBundleAsVirtualFile = (ResourceBundleAsVirtualFile)o; - if (!myBasePropertiesFile.equals(resourceBundleAsVirtualFile.myBasePropertiesFile)) return false; + if (!myResourceBundle.equals(resourceBundleAsVirtualFile.myResourceBundle)) return false; return true; } public int hashCode() { - return myBasePropertiesFile.hashCode(); + return myResourceBundle.hashCode(); } @Override @@ -114,7 +100,7 @@ public class ResourceBundleAsVirtualFile extends VirtualFile { @Override public VirtualFile getParent() { - return myBasePropertiesFile.getParent(); + return myResourceBundle.getBaseDirectory(); } @Override diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java index 39e9ed67e7b2..27deebbff2af 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java @@ -170,7 +170,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit TreeElement[] children = myStructureViewComponent.getTreeModel().getRoot().getChildren(); if (children.length != 0) { TreeElement child = children[0]; - String propName = ((ResourceBundlePropertyStructureViewElement)child).getValue().getUnescapedKey(); + String propName = ((ResourceBundlePropertyStructureViewElement)child).getProperty().getUnescapedKey(); setState(new ResourceBundleEditorState(propName)); } myDataProviderPanel = new DataProviderPanel(splitPanel); @@ -248,7 +248,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit DefaultMutableTreeNode node = toCheck.pop(); final ResourceBundleEditorViewElement element = getSelectedElement(node); String value = element instanceof ResourceBundlePropertyStructureViewElement - ? ((ResourceBundlePropertyStructureViewElement)element).getValue().getUnescapedKey() + ? ((ResourceBundlePropertyStructureViewElement)element).getProperty().getUnescapedKey() : null; if (propertyName.equals(value)) { nodeToSelect = node; diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java index fdbc2c0c5e59..d70dd358a9a9 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditorProvider.java @@ -50,7 +50,7 @@ public class ResourceBundleEditorProvider extends FileTypeFactory implements Fil public FileEditor createEditor(@NotNull Project project, @NotNull final VirtualFile file){ ResourceBundle resourceBundle; if (file instanceof ResourceBundleAsVirtualFile) { - resourceBundle = ((ResourceBundleAsVirtualFile)file).getResourceBundle(project); + resourceBundle = ((ResourceBundleAsVirtualFile)file).getResourceBundle(); } else { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java index da376abe05b2..f950f613ecb9 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleStructureViewComponent.java @@ -72,7 +72,7 @@ class ResourceBundleStructureViewComponent extends PropertiesGroupingStructureVi public Object getData(final String dataId) { if (CommonDataKeys.VIRTUAL_FILE.is(dataId)) { - return ResourceBundleAsVirtualFile.fromResourceBundle(myResourceBundle); + return new ResourceBundleAsVirtualFile(myResourceBundle); } else if (PlatformDataKeys.FILE_EDITOR.is(dataId)) { return getFileEditor(); } else if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) { diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java index e4a35e7e677c..51c3764b7f2e 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleUtil.java @@ -56,7 +56,7 @@ public class ResourceBundleUtil { } final Project project = CommonDataKeys.PROJECT.getData(dataContext); if (virtualFile instanceof ResourceBundleAsVirtualFile && project != null) { - return ((ResourceBundleAsVirtualFile)virtualFile).getResourceBundle(project); + return ((ResourceBundleAsVirtualFile)virtualFile).getResourceBundle(); } if (project != null) { final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile); diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/CustomResourceBundlePropertiesFileNode.java b/plugins/properties/src/com/intellij/lang/properties/projectView/CustomResourceBundlePropertiesFileNode.java new file mode 100644 index 000000000000..605b8c843a47 --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/CustomResourceBundlePropertiesFileNode.java @@ -0,0 +1,56 @@ +/* + * 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.lang.properties.projectView; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.PsiFileNode; +import com.intellij.lang.properties.PropertiesBundle; +import com.intellij.lang.properties.PropertiesImplUtil; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.ui.SimpleTextAttributes; + +/** + * @author Dmitry Batkovich + */ +public class CustomResourceBundlePropertiesFileNode extends PsiFileNode { + public CustomResourceBundlePropertiesFileNode(Project project, PsiFile value, ViewSettings viewSettings) { + super(project, value, viewSettings); + setUpdateCount(-1); + } + + @Override + public void update(PresentationData data) { + super.update(data); + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(getValue()); + assert propertiesFile != null; + final ResourceBundle resourceBundle = propertiesFile.getResourceBundle(); + data.setLocationString(PropertiesBundle.message("project.view.resource.bundle.tree.node.text", resourceBundle.getBaseName())); + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof CustomResourceBundlePropertiesFileNode)) { + return false; + } + return Comparing.equal(getValue(), ((CustomResourceBundlePropertiesFileNode)object).getValue()); + } +} diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleGrouper.java b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleGrouper.java index 0ac072c062c2..f6f268df3597 100644 --- a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleGrouper.java +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleGrouper.java @@ -18,6 +18,7 @@ package com.intellij.lang.properties.projectView; import com.intellij.ide.projectView.TreeStructureProvider; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.lang.properties.CustomResourceBundle; import com.intellij.lang.properties.PropertiesImplUtil; import com.intellij.lang.properties.ResourceBundle; import com.intellij.lang.properties.psi.PropertiesFile; @@ -83,6 +84,10 @@ public class ResourceBundleGrouper implements TreeStructureProvider, DumbAware { ResourceBundle bundle = propertiesFile.getResourceBundle(); if (childBundles.get(bundle).size() != 1) { continue; + } else if (bundle instanceof CustomResourceBundle) { + final CustomResourceBundlePropertiesFileNode node = + new CustomResourceBundlePropertiesFileNode(myProject, (PsiFile)f, settings); + result.add(node); } } } diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java index a415e4544aa0..b9f61643095d 100644 --- a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java @@ -86,7 +86,7 @@ public class ResourceBundleNode extends ProjectViewNode<ResourceBundle>{ } public void navigate(final boolean requestFocus) { - OpenFileDescriptor descriptor = new OpenFileDescriptor(getProject(), ResourceBundleAsVirtualFile.fromResourceBundle(getValue())); + OpenFileDescriptor descriptor = new OpenFileDescriptor(getProject(), new ResourceBundleAsVirtualFile(getValue())); FileEditorManager.getInstance(getProject()).openTextEditor(descriptor, requestFocus); } diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java index f3c81736673f..6f0d52f1c294 100644 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/RenamePropertyProcessor.java @@ -46,7 +46,7 @@ public class RenamePropertyProcessor extends RenamePsiElementProcessor { allRenames.clear(); for (final Map.Entry<PsiElement, String> e : allRenamesCopy.entrySet()) { final IProperty property = (IProperty) e.getKey(); - final List<IProperty> properties = PropertiesUtil.findAllProperties(project, resourceBundle, property.getUnescapedKey()); + final List<IProperty> properties = PropertiesUtil.findAllProperties(resourceBundle, property.getUnescapedKey()); for (final IProperty toRename : properties) { allRenames.put(toRename.getPsiElement(), e.getValue()); } diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java index ab1b4391b0f6..000f72ef5ae3 100644 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/rename/ResourceBundleRenamer.java @@ -16,7 +16,7 @@ package com.intellij.lang.properties.refactoring.rename; import com.intellij.lang.properties.PropertiesBundle; -import com.intellij.lang.properties.PropertiesUtil; +import com.intellij.lang.properties.ResourceBundleManager; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiNamedElement; @@ -28,7 +28,10 @@ import org.jetbrains.annotations.NonNls; */ public class ResourceBundleRenamer extends AutomaticRenamer { + private final ResourceBundleManager myResourceBundleManager; + public ResourceBundleRenamer(final PropertiesFile propertiesFile, final String newName) { + myResourceBundleManager = ResourceBundleManager.getInstance(propertiesFile.getProject()); for (final PropertiesFile file : propertiesFile.getResourceBundle().getPropertiesFiles()) { if (file.equals(propertiesFile)) { continue; @@ -41,12 +44,12 @@ public class ResourceBundleRenamer extends AutomaticRenamer { @Override protected String nameToCanonicalName(@NonNls final String name, final PsiNamedElement element) { - return PropertiesUtil.getBaseName((PsiFile)element); + return myResourceBundleManager.getBaseName((PsiFile)element); } @Override protected String canonicalNameToName(@NonNls final String canonicalName, final PsiNamedElement element) { - final String oldCanonicalName = PropertiesUtil.getBaseName((PsiFile)element); + final String oldCanonicalName = myResourceBundleManager.getBaseName((PsiFile)element); final String oldName = element.getName(); assert oldName != null; return canonicalName + oldName.substring(oldCanonicalName.length()); diff --git a/plugins/properties/testSrc/com/intellij/lang/properties/CustomResourceBundleTest.java b/plugins/properties/testSrc/com/intellij/lang/properties/CustomResourceBundleTest.java new file mode 100644 index 000000000000..69e8621ac8db --- /dev/null +++ b/plugins/properties/testSrc/com/intellij/lang/properties/CustomResourceBundleTest.java @@ -0,0 +1,139 @@ +/* + * 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.lang.properties; + +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; + +import java.io.IOException; +import java.util.Locale; + +import static com.intellij.util.containers.ContainerUtil.list; +import static com.intellij.util.containers.ContainerUtil.map; + +/** + * @author Dmitry Batkovich + */ +public class CustomResourceBundleTest extends LightPlatformCodeInsightFixtureTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + ResourceBundleManager.getInstance(getProject()).loadState(new ResourceBundleManagerState()); + } + + public void testDissociateDefaultBaseName() { + final PsiFile file = myFixture.addFileToProject("some_property_file.properties", ""); + final PsiFile file2 = myFixture.addFileToProject("some_property_filee.properties", ""); + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(file); + assertNotNull(propertiesFile); + final ResourceBundle resourceBundle = propertiesFile.getResourceBundle(); + final ResourceBundleManager resourceBundleBaseNameManager = ResourceBundleManager.getInstance(getProject()); + resourceBundleBaseNameManager.dissociateResourceBundle(resourceBundle); + for (final PsiFile psiFile : list(file, file2)) { + assertEquals(psiFile.getVirtualFile().getNameWithoutExtension(), resourceBundleBaseNameManager.getBaseName(psiFile)); + final PropertiesFile somePropertyFile = PropertiesImplUtil.getPropertiesFile(file); + assertNotNull(somePropertyFile); + assertOneElement(somePropertyFile.getResourceBundle().getPropertiesFiles()); + } + } + + public void testCombineToCustomResourceBundleAndDissociateAfter() { + final PropertiesFile file = PropertiesImplUtil.getPropertiesFile(myFixture.addFileToProject("resources-dev/my-app-dev.properties", "")); + final PropertiesFile file2 = PropertiesImplUtil.getPropertiesFile(myFixture.addFileToProject("resources-prod/my-app-prod.properties", "")); + assertNotNull(file); + assertNotNull(file2); + assertOneElement(file.getResourceBundle().getPropertiesFiles()); + assertOneElement(file2.getResourceBundle().getPropertiesFiles()); + + final ResourceBundleManager resourceBundleBaseNameManager = ResourceBundleManager.getInstance(getProject()); + final String newBaseName = "my-app"; + resourceBundleBaseNameManager.combineToResourceBundle(list(file, file2), newBaseName); + final ResourceBundle resourceBundle = file.getResourceBundle(); + assertEquals(2, resourceBundle.getPropertiesFiles().size()); + assertEquals(newBaseName, resourceBundle.getBaseName()); + + resourceBundleBaseNameManager.dissociateResourceBundle(resourceBundle); + assertOneElement(file.getResourceBundle().getPropertiesFiles()); + assertOneElement(file2.getResourceBundle().getPropertiesFiles()); + } + + public void testCustomResourceBundleFilesMovedOrDeleted() throws IOException { + final PropertiesFile file = PropertiesImplUtil.getPropertiesFile(myFixture.addFileToProject("resources-dev/my-app-dev.properties", "")); + final PropertiesFile file2 = PropertiesImplUtil.getPropertiesFile(myFixture.addFileToProject("resources-dev/my-app-test.properties", "")); + final PropertiesFile file3 = PropertiesImplUtil.getPropertiesFile(myFixture.addFileToProject("resources-prod/my-app-prod.properties", "")); + assertNotNull(file); + assertNotNull(file2); + assertNotNull(file3); + assertOneElement(file.getResourceBundle().getPropertiesFiles()); + assertOneElement(file2.getResourceBundle().getPropertiesFiles()); + assertOneElement(file3.getResourceBundle().getPropertiesFiles()); + final ResourceBundleManager resourceBundleBaseNameManager = ResourceBundleManager.getInstance(getProject()); + resourceBundleBaseNameManager.combineToResourceBundle(list(file, file2, file3), "my-app"); + + assertSize(3, file.getResourceBundle().getPropertiesFiles()); + + final PsiDirectory newDir = PsiManager.getInstance(getProject()).findDirectory(myFixture.getTempDirFixture().findOrCreateDir("new-resources-dir")); + new MoveFilesOrDirectoriesProcessor(getProject(), new PsiElement[] {file2.getContainingFile()}, newDir, false, false, null, null).run(); + file3.getContainingFile().delete(); + + assertSize(2, file.getResourceBundle().getPropertiesFiles()); + + final ResourceBundleManagerState state = ResourceBundleManager.getInstance(getProject()).getState(); + assertNotNull(state); + assertSize(1, state.getCustomResourceBundles()); + assertSize(2, state.getCustomResourceBundles().get(0).getFileUrls()); + } + + public void testLocaleIfCanExtractFromCustomResourceBundle() { + final PsiFile file = myFixture.addFileToProject("Base_Page.properties", ""); + final PsiFile file2 = myFixture.addFileToProject("Base_Page_en.properties", ""); + final ResourceBundleManager resourceBundleBaseNameManager = ResourceBundleManager.getInstance(getProject()); + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(file); + assertNotNull(propertiesFile); + resourceBundleBaseNameManager.dissociateResourceBundle(propertiesFile.getResourceBundle()); + resourceBundleBaseNameManager.combineToResourceBundle(map(list(file, file2), new Function<PsiFile, PropertiesFile>() { + @Override + public PropertiesFile fun(final PsiFile psiFile) { + return PropertiesImplUtil.getPropertiesFile(psiFile); + } + }), "Base_Page"); + final PropertiesFile propertiesFile2 = PropertiesImplUtil.getPropertiesFile(file2); + assertNotNull(propertiesFile2); + final Locale locale = propertiesFile2.getLocale(); + assertEquals("en", locale.getLanguage()); + } + + public void testSuggestedCustomResourceBundleName() { + final PsiFile file = myFixture.addFileToProject("Base_Page.properties", ""); + final PsiFile file2 = myFixture.addFileToProject("Base_Page_en.properties", ""); + final String baseName = + PropertiesUtil.getDefaultBaseName(ContainerUtil.map(list(file, file2), new Function<PsiFile, PropertiesFile>() { + @Override + public PropertiesFile fun(PsiFile psiFile) { + return PropertiesImplUtil.getPropertiesFile(file); + } + })); + assertEquals("Base_Page", baseName); + } +} diff --git a/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java b/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java index 20c44e9f47e0..44765f96fc69 100644 --- a/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java +++ b/plugins/properties/testSrc/com/intellij/lang/properties/PropertiesUtilTest.java @@ -15,12 +15,7 @@ */ package com.intellij.lang.properties; -import com.intellij.openapi.vfs.newvfs.impl.StubVirtualFile; -import com.intellij.psi.PsiFile; -import com.intellij.psi.impl.FakePsiElement; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; -import junit.framework.TestCase; -import org.jetbrains.annotations.NotNull; /** * @author Dmitry Batkovich @@ -59,18 +54,8 @@ public class PropertiesUtilTest extends LightPlatformCodeInsightFixtureTestCase assertBaseNameEquals("Base_Properties.utf8.properties", "Base_Properties.utf8"); } - public void _test1() { - assertBaseNameEquals("Base_Page_fr.utf8.properties", "Base_Page.utf8"); - } - public void _test2() { - assertBaseNameEquals("Base_Page_en.utf8.properties", "Base_Page.utf8"); - } - public void _test3() { - assertBaseNameEquals("Base_Page.utf8.properties", "Base_Page.utf8"); - } - private void assertBaseNameEquals(final String propertyFileName, final String expectedBaseName) { - final String actualBaseName = PropertiesUtil.getBaseName(myFixture.configureByText(propertyFileName, "")); + final String actualBaseName = ResourceBundleManager.getInstance(getProject()).getBaseName(myFixture.configureByText(propertyFileName, "")); assertEquals(expectedBaseName, actualBaseName); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index aaf46003c1dd..cd0a321d5a58 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -790,7 +790,9 @@ public class SvnUtil { e.contains(SVNErrorCode.UNVERSIONED_RESOURCE) || e.contains(SVNErrorCode.WC_NOT_WORKING_COPY) || // thrown when getting info from repository for non-existent item - like HEAD revision for deleted file - e.contains(SVNErrorCode.ILLEGAL_TARGET); + e.contains(SVNErrorCode.ILLEGAL_TARGET) || + // for svn 1.6 + StringUtil.containsIgnoreCase(e.getMessage(), "(not a versioned resource)"); } // TODO: Create custom Target class and implement append there diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index e5018f3319d5..f4f3ee98f549 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -32,6 +32,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Trinity; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.annotate.AnnotationProvider; import com.intellij.openapi.vcs.changes.*; @@ -63,10 +64,7 @@ import org.jetbrains.idea.svn.actions.CleanupWorker; import org.jetbrains.idea.svn.actions.ShowPropertiesDiffWithLocalAction; import org.jetbrains.idea.svn.actions.SvnMergeProvider; import org.jetbrains.idea.svn.annotate.SvnAnnotationProvider; -import org.jetbrains.idea.svn.api.ClientFactory; -import org.jetbrains.idea.svn.api.CmdClientFactory; -import org.jetbrains.idea.svn.api.Depth; -import org.jetbrains.idea.svn.api.SvnKitClientFactory; +import org.jetbrains.idea.svn.api.*; import org.jetbrains.idea.svn.auth.SvnAuthenticationNotifier; import org.jetbrains.idea.svn.branchConfig.SvnLoadedBranchesStorage; import org.jetbrains.idea.svn.checkin.SvnCheckinEnvironment; @@ -264,13 +262,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { } public boolean checkCommandLineVersion() { - boolean isValid = true; - - if (!isProject16() && (myConfiguration.isCommandLine() || isProject18OrGreater())) { - isValid = myChecker.checkExecutableAndNotifyIfNeeded(); - } - - return isValid; + return getFactory() != cmdClientFactory || myChecker.checkExecutableAndNotifyIfNeeded(); } public void invokeRefreshSvnRoots() { @@ -922,13 +914,9 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { @Override public boolean isVcsBackgroundOperationsAllowed(@NotNull VirtualFile root) { - // TODO: Currently myAuthNotifier.isAuthenticatedFor directly uses SVNKit to check credentials - so assume for now that background - // TODO: operations are always allowed for command line. As sometimes this leads to errors - for instance, incoming changes are not - // TODO: displayed in "Incoming" tab - incoming changes are collected using command line but not displayed because - // TODO: SvnVcs.isVcsBackgroundOperationsAllowed is false. ClientFactory factory = getFactory(VfsUtilCore.virtualToIoFile(root)); - return factory == cmdClientFactory || ThreeState.YES.equals(myAuthNotifier.isAuthenticatedFor(root)); + return ThreeState.YES.equals(myAuthNotifier.isAuthenticatedFor(root, factory == cmdClientFactory ? factory : null)); } public SvnBranchPointsCalculator getSvnBranchPointsCalculator() { @@ -953,14 +941,6 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { return svnKitManager; } - public boolean isProject18OrGreater() { - return getProjectRootFormat().isOrGreater(WorkingCopyFormat.ONE_DOT_EIGHT); - } - - public boolean isProject16() { - return WorkingCopyFormat.ONE_DOT_SIX.equals(getProjectRootFormat()); - } - @NotNull private WorkingCopyFormat getProjectRootFormat() { return !getProject().isDefault() ? getWorkingCopyFormat(new File(getProject().getBaseDir().getPath())) : WorkingCopyFormat.UNKNOWN; @@ -1000,12 +980,13 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { @NotNull private ClientFactory getFactory(@NotNull WorkingCopyFormat format, boolean useProjectRootForUnknown) { boolean is18OrGreater = format.isOrGreater(WorkingCopyFormat.ONE_DOT_EIGHT); - boolean is16 = WorkingCopyFormat.ONE_DOT_SIX.equals(format); boolean isUnknown = WorkingCopyFormat.UNKNOWN.equals(format); return is18OrGreater ? cmdClientFactory - : (is16 ? svnKitClientFactory : (useProjectRootForUnknown && isUnknown ? getFactory() : getFactoryFromSettings())); + : (!isUnknown && !isSupportedByCommandLine(format) + ? svnKitClientFactory + : (useProjectRootForUnknown && isUnknown ? getFactory() : getFactoryFromSettings())); } @NotNull @@ -1037,4 +1018,26 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { public ClientFactory getSvnKitFactory() { return svnKitClientFactory; } + + @NotNull + public WorkingCopyFormat getLowestSupportedFormatForCommandLine() { + WorkingCopyFormat result; + + try { + result = WorkingCopyFormat.from(CmdVersionClient.parseVersion(Registry.stringValue("svn.lowest.supported.format.for.command.line"))); + } + catch (SvnBindException ignore) { + result = WorkingCopyFormat.ONE_DOT_SEVEN; + } + + return result; + } + + public boolean isSupportedByCommandLine(@NotNull WorkingCopyFormat format) { + return format.isOrGreater(getLowestSupportedFormatForCommandLine()); + } + + public boolean is16SupportedByCommandLine() { + return isSupportedByCommandLine(WorkingCopyFormat.ONE_DOT_SIX); + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopy.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopy.java index 9b6530e3a914..0a23df56daad 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopy.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopy.java @@ -15,25 +15,29 @@ */ package org.jetbrains.idea.svn; +import org.jetbrains.annotations.NotNull; import org.tmatesoft.svn.core.SVNURL; import java.io.File; public class WorkingCopy { private final boolean myIs17Copy; - private final File myFile; - private final SVNURL myUrl; + @NotNull private final File myFile; + @NotNull private final SVNURL myUrl; - public WorkingCopy(File file, SVNURL url, boolean is17Copy) { + // TODO: is17Copy is currently true in all constructor usages - remove this field and revise is17Copy() usages + public WorkingCopy(@NotNull File file, @NotNull SVNURL url, boolean is17Copy) { myFile = file; myUrl = url; myIs17Copy = is17Copy; } + @NotNull public File getFile() { return myFile; } + @NotNull public SVNURL getUrl() { return myUrl; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java index 0d58355543ba..01689e586f81 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java @@ -6,13 +6,16 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.WorkingCopyFormat; -import org.jetbrains.idea.svn.auth.IdeaSvnkitBasedAuthenticationCallback; +import org.jetbrains.idea.svn.auth.AuthenticationService; import org.jetbrains.idea.svn.commandLine.*; import org.jetbrains.idea.svn.diff.DiffOptions; import org.tmatesoft.svn.core.SVNCancelException; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.wc.*; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; +import org.tmatesoft.svn.core.wc.SVNDiffOptions; +import org.tmatesoft.svn.core.wc.SVNEvent; +import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; @@ -25,6 +28,7 @@ import java.util.List; public abstract class BaseSvnClient implements SvnClient { protected SvnVcs myVcs; protected ClientFactory myFactory; + protected boolean myIsActive; @NotNull @Override @@ -48,6 +52,11 @@ public abstract class BaseSvnClient implements SvnClient { myFactory = factory; } + @Override + public void setIsActive(boolean isActive) { + myIsActive = isActive; + } + protected void assertUrl(@NotNull SvnTarget target) { if (!target.isURL()) { throw new IllegalArgumentException("Target should be url " + target); @@ -74,31 +83,22 @@ public abstract class BaseSvnClient implements SvnClient { } } - /** - * Utility method for running commands. - * // TODO: Should be replaced with non-static analogue. - * - * @param vcs - * @param target - * @param name - * @param parameters - * @param listener - * @throws com.intellij.openapi.vcs.VcsException - */ - public static CommandExecutor execute(@NotNull SvnVcs vcs, - @NotNull SvnTarget target, - @NotNull SvnCommandName name, - @NotNull List<String> parameters, - @Nullable LineCommandListener listener) throws SvnBindException { + @NotNull + public CommandExecutor execute(@NotNull SvnVcs vcs, + @NotNull SvnTarget target, + @NotNull SvnCommandName name, + @NotNull List<String> parameters, + @Nullable LineCommandListener listener) throws SvnBindException { return execute(vcs, target, null, name, parameters, listener); } - public static CommandExecutor execute(@NotNull SvnVcs vcs, - @NotNull SvnTarget target, - @Nullable File workingDirectory, - @NotNull SvnCommandName name, - @NotNull List<String> parameters, - @Nullable LineCommandListener listener) throws SvnBindException { + @NotNull + public CommandExecutor execute(@NotNull SvnVcs vcs, + @NotNull SvnTarget target, + @Nullable File workingDirectory, + @NotNull SvnCommandName name, + @NotNull List<String> parameters, + @Nullable LineCommandListener listener) throws SvnBindException { Command command = new Command(name); command.setTarget(target); @@ -106,7 +106,7 @@ public abstract class BaseSvnClient implements SvnClient { command.setResultBuilder(listener); command.put(parameters); - CommandRuntime runtime = new CommandRuntime(vcs, new IdeaSvnkitBasedAuthenticationCallback(vcs)); + CommandRuntime runtime = new CommandRuntime(vcs, new AuthenticationService(vcs, myIsActive)); return runtime.runWithAuthenticationAttempt(command); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java index ba3e56de8e63..4eb5f8b0c7b7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java @@ -1,5 +1,7 @@ package org.jetbrains.idea.svn.api; +import com.intellij.util.ReflectionUtil; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnVcs; @@ -18,17 +20,19 @@ import org.jetbrains.idea.svn.copy.CopyMoveClient; import org.jetbrains.idea.svn.delete.DeleteClient; import org.jetbrains.idea.svn.diff.DiffClient; import org.jetbrains.idea.svn.history.HistoryClient; +import org.jetbrains.idea.svn.info.InfoClient; import org.jetbrains.idea.svn.integrate.MergeClient; import org.jetbrains.idea.svn.lock.LockClient; -import org.jetbrains.idea.svn.info.InfoClient; -import org.jetbrains.idea.svn.status.StatusClient; import org.jetbrains.idea.svn.properties.PropertyClient; import org.jetbrains.idea.svn.revert.RevertClient; +import org.jetbrains.idea.svn.status.StatusClient; import org.jetbrains.idea.svn.update.RelocateClient; import org.jetbrains.idea.svn.update.UpdateClient; import org.jetbrains.idea.svn.upgrade.UpgradeClient; import org.tmatesoft.svn.core.wc.ISVNStatusFileProvider; +import java.util.Map; + /** * @author Konstantin Kolosovsky. */ @@ -63,6 +67,8 @@ public abstract class ClientFactory { protected CheckinClient myCheckinClient; protected RepositoryFeaturesClient myRepositoryFeaturesClient; + @NotNull private final Map<Class, Class> myClientImplementations = ContainerUtil.newHashMap(); + protected ClientFactory(@NotNull SvnVcs vcs) { myVcs = vcs; setup(); @@ -70,6 +76,33 @@ public abstract class ClientFactory { protected abstract void setup(); + protected <T extends SvnClient> void put(@NotNull Class<T> type, @NotNull Class<? extends T> implementation) { + myClientImplementations.put(type, implementation); + } + + @SuppressWarnings("unchecked") + @NotNull + protected <T extends SvnClient> Class<? extends T> get(@NotNull Class<T> type) { + Class<? extends T> implementation = myClientImplementations.get(type); + + if (implementation == null) { + throw new IllegalArgumentException("No implementation registered for " + type); + } + + return implementation; + } + + /** + * TODO: Provide more robust way for the default settings here - probably some default Command instance could be used. + */ + @NotNull + public <T extends SvnClient> T create(@NotNull Class<T> type, boolean isActive) { + T client = prepare(ReflectionUtil.newInstance(get(type))); + client.setIsActive(isActive); + + return client; + } + @NotNull public AddClient createAddClient() { return prepare(addClient); @@ -209,6 +242,7 @@ public abstract class ClientFactory { protected <T extends SvnClient> T prepare(@NotNull T client) { client.setVcs(myVcs); client.setFactory(this); + client.setIsActive(true); return client; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java index 54639b9e120b..6a5b9e8076f2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.CmdAddClient; import org.jetbrains.idea.svn.annotate.CmdAnnotateClient; +import org.jetbrains.idea.svn.browse.BrowseClient; import org.jetbrains.idea.svn.browse.CmdBrowseClient; import org.jetbrains.idea.svn.change.CmdChangeListClient; import org.jetbrains.idea.svn.checkin.CmdCheckinClient; @@ -11,18 +12,19 @@ import org.jetbrains.idea.svn.checkin.CmdImportClient; import org.jetbrains.idea.svn.checkout.CmdCheckoutClient; import org.jetbrains.idea.svn.checkout.CmdExportClient; import org.jetbrains.idea.svn.cleanup.CmdCleanupClient; -import org.jetbrains.idea.svn.status.CmdStatusClient; -import org.jetbrains.idea.svn.info.CmdInfoClient; import org.jetbrains.idea.svn.conflict.CmdConflictClient; import org.jetbrains.idea.svn.content.CmdContentClient; import org.jetbrains.idea.svn.copy.CmdCopyMoveClient; import org.jetbrains.idea.svn.delete.CmdDeleteClient; import org.jetbrains.idea.svn.diff.CmdDiffClient; import org.jetbrains.idea.svn.history.CmdHistoryClient; +import org.jetbrains.idea.svn.info.CmdInfoClient; +import org.jetbrains.idea.svn.info.InfoClient; import org.jetbrains.idea.svn.integrate.CmdMergeClient; import org.jetbrains.idea.svn.lock.CmdLockClient; import org.jetbrains.idea.svn.properties.CmdPropertyClient; import org.jetbrains.idea.svn.revert.CmdRevertClient; +import org.jetbrains.idea.svn.status.CmdStatusClient; import org.jetbrains.idea.svn.update.CmdRelocateClient; import org.jetbrains.idea.svn.update.CmdUpdateClient; import org.jetbrains.idea.svn.update.UpdateClient; @@ -64,6 +66,9 @@ public class CmdClientFactory extends ClientFactory { statusClient = new CmdStatusClient(); infoClient = new CmdInfoClient(); myRepositoryFeaturesClient = new CmdRepositoryFeaturesClient(); + + put(BrowseClient.class, CmdBrowseClient.class); + put(InfoClient.class, CmdInfoClient.class); } @NotNull diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdVersionClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdVersionClient.java index c3acfdc7c561..5b1484944285 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdVersionClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdVersionClient.java @@ -2,7 +2,6 @@ package org.jetbrains.idea.svn.api; import com.intellij.execution.process.ProcessOutput; import com.intellij.openapi.util.Version; -import com.intellij.openapi.vcs.VcsException; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnApplicationSettings; import org.jetbrains.idea.svn.commandLine.Command; @@ -22,7 +21,7 @@ public class CmdVersionClient extends BaseSvnClient implements VersionClient { @NotNull @Override - public Version getVersion() throws VcsException { + public Version getVersion() throws SvnBindException { return parseVersion(runCommand()); } @@ -38,9 +37,9 @@ public class CmdVersionClient extends BaseSvnClient implements VersionClient { } @NotNull - private static Version parseVersion(@NotNull ProcessOutput output) throws VcsException { + private static Version parseVersion(@NotNull ProcessOutput output) throws SvnBindException { if (output.isTimeout() || (output.getExitCode() != 0) || !output.getStderr().isEmpty()) { - throw new VcsException( + throw new SvnBindException( String.format("Exit code: %d, Error: %s, Timeout: %b", output.getExitCode(), output.getStderr(), output.isTimeout())); } @@ -48,7 +47,7 @@ public class CmdVersionClient extends BaseSvnClient implements VersionClient { } @NotNull - public static Version parseVersion(@NotNull String versionText) throws VcsException { + public static Version parseVersion(@NotNull String versionText) throws SvnBindException { Version result = null; Exception cause = null; @@ -65,7 +64,7 @@ public class CmdVersionClient extends BaseSvnClient implements VersionClient { } if (!found || cause != null) { - throw new VcsException(String.format("Could not parse svn version: %s", versionText), cause); + throw new SvnBindException(String.format("Could not parse svn version: %s", versionText), cause); } return result; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnClient.java index fcf100f62513..14bc054a4127 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnClient.java @@ -17,4 +17,6 @@ public interface SvnClient { void setVcs(@NotNull SvnVcs vcs); void setFactory(@NotNull ClientFactory factory); + + void setIsActive(boolean isActive); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java index f46f5f06ebdb..95b17d95add8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.add.SvnKitAddClient; import org.jetbrains.idea.svn.annotate.SvnKitAnnotateClient; +import org.jetbrains.idea.svn.browse.BrowseClient; import org.jetbrains.idea.svn.browse.SvnKitBrowseClient; import org.jetbrains.idea.svn.change.SvnKitChangeListClient; import org.jetbrains.idea.svn.checkin.SvnKitCheckinClient; @@ -67,6 +68,8 @@ public class SvnKitClientFactory extends ClientFactory { statusClient = new SvnKitStatusClient(); infoClient = new SvnKitInfoClient(); myRepositoryFeaturesClient = new SvnKitRepositoryFeaturesClient(); + + put(BrowseClient.class, SvnKitBrowseClient.class); } @NotNull diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitVersionClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitVersionClient.java index 084f7f79d946..d0f5da5ad491 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitVersionClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitVersionClient.java @@ -1,7 +1,6 @@ package org.jetbrains.idea.svn.api; import com.intellij.openapi.util.Version; -import com.intellij.openapi.vcs.VcsException; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.WorkingCopyFormat; @@ -12,7 +11,7 @@ public class SvnKitVersionClient extends BaseSvnClient implements VersionClient @NotNull @Override - public Version getVersion() throws VcsException { + public Version getVersion() { return WorkingCopyFormat.ONE_DOT_SEVEN.getVersion(); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/VersionClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/VersionClient.java index bbd70921d7a0..a37cbc17b13a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/VersionClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/VersionClient.java @@ -1,8 +1,8 @@ package org.jetbrains.idea.svn.api; import com.intellij.openapi.util.Version; -import com.intellij.openapi.vcs.VcsException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.commandLine.SvnBindException; /** * @author Konstantin Kolosovsky. @@ -10,5 +10,5 @@ import org.jetbrains.annotations.NotNull; public interface VersionClient extends SvnClient { @NotNull - Version getVersion() throws VcsException; + Version getVersion() throws SvnBindException; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AbstractAuthenticator.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AbstractAuthenticator.java index 203265dea263..0c11d5a488e6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AbstractAuthenticator.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AbstractAuthenticator.java @@ -39,16 +39,16 @@ abstract class AbstractAuthenticator { private static final Logger LOG = Logger.getInstance(AbstractAuthenticator.class); - @NotNull protected final IdeaSvnkitBasedAuthenticationCallback myAuthService; + @NotNull protected final AuthenticationService myAuthenticationService; @NotNull protected final SvnVcs myVcs; @NotNull protected final SVNURL myUrl; protected final String myRealm; protected boolean myStoreInUsual; protected SvnAuthenticationManager myTmpDirManager; - AbstractAuthenticator(@NotNull IdeaSvnkitBasedAuthenticationCallback authService, @NotNull SVNURL url, String realm) { - myAuthService = authService; - myVcs = myAuthService.getVcs(); + AbstractAuthenticator(@NotNull AuthenticationService authenticationService, @NotNull SVNURL url, String realm) { + myAuthenticationService = authenticationService; + myVcs = myAuthenticationService.getVcs(); myUrl = url; myRealm = realm; } @@ -58,7 +58,7 @@ abstract class AbstractAuthenticator { final SvnAuthenticationManager active = myVcs.getSvnConfiguration().getAuthenticationManager(myVcs); try { - boolean authenticated = getWithPassive(passive) || getWithActive(active); + boolean authenticated = getWithPassive(passive) || (myAuthenticationService.isActive() && getWithActive(active)); if (!authenticated) return false; SvnAuthenticationManager manager = myStoreInUsual ? active : createTmpManager(); @@ -80,8 +80,8 @@ abstract class AbstractAuthenticator { @NotNull protected SvnAuthenticationManager createTmpManager() throws IOException { if (myTmpDirManager == null) { - myAuthService.initTmpDir(myVcs.getSvnConfiguration()); - myTmpDirManager = new SvnAuthenticationManager(myVcs.getProject(), myAuthService.getTempDirectory()); + myAuthenticationService.initTmpDir(myVcs.getSvnConfiguration()); + myTmpDirManager = new SvnAuthenticationManager(myVcs.getProject(), myAuthenticationService.getTempDirectory()); myTmpDirManager.setRuntimeStorage(SvnConfiguration.RUNTIME_AUTH_CACHE); myTmpDirManager.setAuthenticationProvider(new SvnInteractiveAuthenticationProvider(myVcs, myTmpDirManager)); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/IdeaSvnkitBasedAuthenticationCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java index 5b77f78aa7e1..9fb377e1dafe 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/IdeaSvnkitBasedAuthenticationCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java @@ -20,7 +20,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.util.PopupUtil; import com.intellij.openapi.util.Getter; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.WaitForProgressToShow; @@ -32,7 +31,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnConfiguration; import org.jetbrains.idea.svn.SvnVcs; -import org.jetbrains.idea.svn.commandLine.AuthenticationCallback; import org.jetbrains.idea.svn.dialogs.SimpleCredentialsDialog; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; @@ -52,16 +50,19 @@ import java.util.Set; * Date: 2/26/13 * Time: 1:27 PM */ -public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCallback { +public class AuthenticationService { + @NotNull private final SvnVcs myVcs; - private static final Logger LOG = Logger.getInstance(IdeaSvnkitBasedAuthenticationCallback.class); + private final boolean myIsActive; + private static final Logger LOG = Logger.getInstance(AuthenticationService.class); private File myTempDirectory; private boolean myProxyCredentialsWereReturned; private SvnConfiguration myConfiguration; private final Set<String> myRequestedCredentials; - public IdeaSvnkitBasedAuthenticationCallback(@NotNull SvnVcs vcs) { + public AuthenticationService(@NotNull SvnVcs vcs, boolean isActive) { myVcs = vcs; + myIsActive = isActive; myConfiguration = SvnConfiguration.getInstance(myVcs.getProject()); myRequestedCredentials = ContainerUtil.newHashSet(); } @@ -76,8 +77,11 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall return myTempDirectory; } - @Override - public boolean authenticateFor(String realm, SVNURL repositoryUrl, boolean previousFailed, boolean passwordRequest) { + public boolean isActive() { + return myIsActive; + } + + public boolean authenticateFor(@Nullable String realm, SVNURL repositoryUrl, boolean passwordRequest) { if (repositoryUrl == null) { return false; } @@ -85,20 +89,17 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall } @Nullable - @Override public SVNAuthentication requestCredentials(final SVNURL repositoryUrl, final String type) { SVNAuthentication authentication = null; if (repositoryUrl != null) { final String realm = repositoryUrl.toDecodedString(); - authentication = requestCredentials(realm, type, new Getter<Pair<SVNAuthentication, Boolean>>() { + authentication = requestCredentials(realm, type, new Getter<SVNAuthentication>() { @Override - public Pair<SVNAuthentication, Boolean> get() { - SVNAuthentication result = myVcs.getSvnConfiguration().getInteractiveManager(myVcs).getInnerProvider() + public SVNAuthentication get() { + return myVcs.getSvnConfiguration().getInteractiveManager(myVcs).getInnerProvider() .requestClientAuthentication(type, repositoryUrl, realm, null, null, true); - - return new Pair<SVNAuthentication, Boolean>(result, true); } }); } @@ -111,8 +112,8 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall } @Nullable - private <T> T requestCredentials(@NotNull String realm, @NotNull String type, @NotNull Getter<Pair<T, Boolean>> fromUserProvider) { - T result; + private <T> T requestCredentials(@NotNull String realm, @NotNull String type, @NotNull Getter<T> fromUserProvider) { + T result = null; // Search for stored credentials not only by key but also by "parent" keys. This is useful when we work just with URLs // (not working copy) and can't detect repository url beforehand because authentication is required. If found credentials of "parent" // are not correct then current key will already be stored in myRequestedCredentials - thus user will be asked for credentials and @@ -126,12 +127,10 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall result = (T)data; myRequestedCredentials.add(key); } - else { + else if (myIsActive) { // ask user for credentials - Pair<T, Boolean> userData = fromUserProvider.get(); - result = userData.first; - - if (result != null && userData.second) { + result = fromUserProvider.get(); + if (result != null) { // save user credentials to memory cache myVcs.getSvnConfiguration().acknowledge(type, realm, result); myRequestedCredentials.add(key); @@ -141,14 +140,13 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall return result; } - @Override @Nullable public String requestSshCredentials(@NotNull final String realm, @NotNull final SimpleCredentialsDialog.Mode mode, @NotNull final String key) { - return requestCredentials(realm, ISVNAuthenticationManager.SSH, new Getter<Pair<String, Boolean>>() { + return requestCredentials(realm, ISVNAuthenticationManager.SSH, new Getter<String>() { @Override - public Pair<String, Boolean> get() { + public String get() { final Ref<String> answer = new Ref<String>(); Runnable command = new Runnable() { @@ -169,12 +167,11 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall // the thread that started progress WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(command, ModalityState.any()); - return new Pair<String, Boolean>(answer.get(), true); + return answer.get(); } }); } - @Override public boolean acceptSSLServerCertificate(final SVNURL repositoryUrl, final String realm) { if (repositoryUrl == null) { return false; @@ -183,7 +180,6 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall return new SSLServerCertificateAuthenticator(this, repositoryUrl, realm).tryAuthenticate(); } - @Override public void clearPassiveCredentials(String realm, SVNURL repositoryUrl, boolean password) { if (repositoryUrl == null) { return; @@ -197,7 +193,6 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall } } - @Override public boolean haveDataForTmpConfig() { final HttpConfigurable instance = HttpConfigurable.getInstance(); return SvnConfiguration.getInstance(myVcs.getProject()).isIsUseDefaultProxy() && @@ -227,7 +222,6 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall return null; } - @Override @Nullable public PasswordAuthentication getProxyAuthentication(@NotNull SVNURL repositoryUrl) { Proxy proxy = getIdeaDefinedProxy(repositoryUrl); @@ -296,7 +290,6 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall } @Nullable - @Override public File getSpecialConfigDir() { return myTempDirectory != null ? myTempDirectory : new File(myConfiguration.getConfigurationDirectory()); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/CredentialsAuthenticator.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/CredentialsAuthenticator.java index 410cb0997201..9658e2adbba7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/CredentialsAuthenticator.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/CredentialsAuthenticator.java @@ -37,14 +37,12 @@ class CredentialsAuthenticator extends AbstractAuthenticator { private String myRealm2; private SVNAuthentication myAuthentication; - CredentialsAuthenticator(@NotNull IdeaSvnkitBasedAuthenticationCallback authService, - @NotNull SVNURL url, - @Nullable String realm) { - super(authService, url, realm == null ? url.getHost() : realm); + CredentialsAuthenticator(@NotNull AuthenticationService authenticationService, @NotNull SVNURL url, @Nullable String realm) { + super(authenticationService, url, realm == null ? url.getHost() : realm); } public boolean tryAuthenticate(boolean passwordRequest) { - final List<String> kinds = IdeaSvnkitBasedAuthenticationCallback.getKinds(myUrl, passwordRequest); + final List<String> kinds = AuthenticationService.getKinds(myUrl, passwordRequest); for (String kind : kinds) { myKind = kind; if (!tryAuthenticate()) { @@ -58,8 +56,8 @@ class CredentialsAuthenticator extends AbstractAuthenticator { protected boolean getWithPassive(SvnAuthenticationManager passive) throws SVNException { myAuthentication = getWithPassiveImpl(passive); if (myAuthentication != null && !checkAuthOk(myAuthentication)) { - myAuthService.clearPassiveCredentials(myRealm, myUrl, - myAuthentication instanceof SVNPasswordAuthentication); //clear passive also take into acconut ssl filepath + //clear passive also take into account ssl file path + myAuthenticationService.clearPassiveCredentials(myRealm, myUrl, myAuthentication instanceof SVNPasswordAuthentication); myAuthentication = null; } return myAuthentication != null; @@ -88,7 +86,7 @@ class CredentialsAuthenticator extends AbstractAuthenticator { if (super.getWithActive(active)) return true; } myAuthentication = active.getProvider().requestClientAuthentication(myKind, myUrl, myRealm, null, null, true); - myStoreInUsual = myAuthService.getTempDirectory() == null && myAuthentication != null && myAuthentication.isStorageAllowed(); + myStoreInUsual = myAuthenticationService.getTempDirectory() == null && myAuthentication != null && myAuthentication.isStorageAllowed(); return myAuthentication != null; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SSLServerCertificateAuthenticator.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SSLServerCertificateAuthenticator.java index 3b78aa55d867..7d76a1fa0536 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SSLServerCertificateAuthenticator.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SSLServerCertificateAuthenticator.java @@ -41,10 +41,8 @@ class SSLServerCertificateAuthenticator extends AbstractAuthenticator { private int myResult; private SVNAuthentication myAuthentication; - SSLServerCertificateAuthenticator(@NotNull IdeaSvnkitBasedAuthenticationCallback authService, - @NotNull SVNURL url, - String realm) { - super(authService, url, realm); + SSLServerCertificateAuthenticator(@NotNull AuthenticationService authenticationService, @NotNull SVNURL url, String realm) { + super(authenticationService, url, realm); } @Override @@ -102,7 +100,7 @@ class SSLServerCertificateAuthenticator extends AbstractAuthenticator { myCertificate = createCertificate(stored); myCertificateRealm = myRealm; } - if (myAuthService.getTempDirectory() != null && myCertificate != null) { + if (myAuthenticationService.getTempDirectory() != null && myCertificate != null) { storeServerCertificate(); if (myAuthentication != null) { @@ -142,7 +140,7 @@ class SSLServerCertificateAuthenticator extends AbstractAuthenticator { } int failures = SVNSSLUtil.getServerCertificateFailures(x509Certificate, myUrl.getHost()); - storeServerCertificate(myAuthService.getTempDirectory(), myCertificateRealm, stored, failures); + storeServerCertificate(myAuthenticationService.getTempDirectory(), myCertificateRealm, stored, failures); } private void storeServerCertificate(final File configDir, String realm, String data, int failures) throws SVNException { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationNotifier.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationNotifier.java index ffc21a011334..29f15423e581 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationNotifier.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationNotifier.java @@ -44,6 +44,10 @@ import com.intellij.util.proxy.CommonProxy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.api.ClientFactory; +import org.jetbrains.idea.svn.commandLine.SvnBindException; +import org.jetbrains.idea.svn.info.Info; +import org.jetbrains.idea.svn.info.InfoClient; import org.tmatesoft.svn.core.SVNAuthenticationException; import org.tmatesoft.svn.core.SVNCancelException; import org.tmatesoft.svn.core.SVNException; @@ -172,6 +176,7 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica } log("on state changed "); ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override public void run() { for (SVNURL key : outdatedRequests) { removeLazyNotificationByKey(key); @@ -223,7 +228,7 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica /** * Bases on presence of notifications! */ - public ThreeState isAuthenticatedFor(@NotNull VirtualFile vf) { + public ThreeState isAuthenticatedFor(@NotNull VirtualFile vf, @Nullable ClientFactory factory) { final WorkingCopy wcCopy = myRootsToWorkingCopies.getWcRoot(vf); if (wcCopy == null) return ThreeState.UNSURE; @@ -236,11 +241,24 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica if (Boolean.FALSE.equals(keptResult)) return ThreeState.NO; // check have credentials - final boolean calculatedResult = passiveValidation(myVcs.getProject(), wcCopy.getUrl()); + final boolean calculatedResult = + factory == null ? passiveValidation(myVcs.getProject(), wcCopy.getUrl()) : passiveValidation(factory, wcCopy.getUrl()); myCopiesPassiveResults.put(wcCopy.getUrl(), calculatedResult); return calculatedResult ? ThreeState.YES : ThreeState.NO; } + private static boolean passiveValidation(@NotNull ClientFactory factory, @NotNull SVNURL url) { + Info info = null; + + try { + info = factory.create(InfoClient.class, false).doInfo(url, SVNRevision.UNDEFINED, SVNRevision.UNDEFINED); + } + catch (SvnBindException ignore) { + } + + return info != null; + } + @NotNull @Override protected String getNotificationContent(AuthenticationRequest obj) { @@ -470,6 +488,7 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica final File authDir = new File(configuration.getConfigurationDirectory(), "auth"); if (authDir.exists()) { final Runnable process = new Runnable() { + @Override public void run() { final ProgressIndicator ind = ProgressManager.getInstance().getProgressIndicator(); if (ind != null) { @@ -477,7 +496,8 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica ind.setText("Clearing stored credentials in " + authDir.getAbsolutePath()); } final File[] files = authDir.listFiles(new FilenameFilter() { - public boolean accept(File dir, String name) { + @Override + public boolean accept(@NotNull File dir, @NotNull String name) { return ourAuthKinds.contains(name); } }); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java index ba0288da9699..a51ce8c13629 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java @@ -21,13 +21,13 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.svn.SvnConfiguration; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.api.Depth; +import org.jetbrains.idea.svn.browse.BrowseClient; import org.jetbrains.idea.svn.browse.DirectoryEntry; import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer; -import org.tmatesoft.svn.core.*; -import org.tmatesoft.svn.core.wc.SVNLogClient; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -75,23 +75,13 @@ public class BranchesLoader implements Runnable { @NotNull public List<SvnBranchItem> loadBranches() throws SVNException, VcsException { - final SvnConfiguration configuration = SvnConfiguration.getInstance(myProject); - final SvnVcs vcs = SvnVcs.getInstance(myProject); + SvnVcs vcs = SvnVcs.getInstance(myProject); SVNURL branchesUrl = SVNURL.parseURIEncoded(myUrl); List<SvnBranchItem> result = new LinkedList<SvnBranchItem>(); SvnTarget target = SvnTarget.fromURL(branchesUrl); + DirectoryEntryConsumer handler = createConsumer(result); - if (!myPassive) { - // TODO: Implement ability to specify interactive/non-interactive auth mode for clients - DirectoryEntryConsumer handler = createConsumer(branchesUrl, result); - vcs.getFactory(target).createBrowseClient().list(target, SVNRevision.HEAD, Depth.IMMEDIATES, handler); - } - else { - ISVNDirEntryHandler handler = createHandler(branchesUrl, result); - SVNLogClient client = vcs.getSvnKitManager().createLogClient(configuration.getPassiveAuthenticationManager(myProject)); - client - .doList(target.getURL(), target.getPegRevision(), SVNRevision.HEAD, false, SVNDepth.IMMEDIATES, SVNDirEntry.DIRENT_ALL, handler); - } + vcs.getFactory(target).create(BrowseClient.class, !myPassive).list(target, SVNRevision.HEAD, Depth.IMMEDIATES, handler); Collections.sort(result); return result; @@ -105,25 +95,12 @@ public class BranchesLoader implements Runnable { } @NotNull - private static ISVNDirEntryHandler createHandler(@NotNull final SVNURL branchesUrl, @NotNull final List<SvnBranchItem> result) { - return new ISVNDirEntryHandler() { - public void handleDirEntry(final SVNDirEntry dirEntry) throws SVNException { - // TODO: Remove equality check with branchesUrl when SVNLogClient will not be used directly, but rather through BrowseClient. - if (!branchesUrl.equals(dirEntry.getURL()) && dirEntry.getDate() != null) { - result.add(new SvnBranchItem(dirEntry.getURL().toDecodedString(), dirEntry.getDate(), dirEntry.getRevision())); - } - } - }; - } - - @NotNull - private static DirectoryEntryConsumer createConsumer(@NotNull final SVNURL branchesUrl, @NotNull final List<SvnBranchItem> result) { + private static DirectoryEntryConsumer createConsumer(@NotNull final List<SvnBranchItem> result) { return new DirectoryEntryConsumer() { @Override public void consume(final DirectoryEntry entry) throws SVNException { - // TODO: Remove equality check with branchesUrl when SVNLogClient will not be used directly, but rather through BrowseClient. - if (!branchesUrl.equals(entry.getUrl()) && entry.getDate() != null) { + if (entry.getDate() != null) { result.add(new SvnBranchItem(entry.getUrl().toDecodedString(), entry.getDate(), entry.getRevision())); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/SvnKitBrowseClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/SvnKitBrowseClient.java index cdbb1ff1e67b..ac1d4a0486df 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/SvnKitBrowseClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/SvnKitBrowseClient.java @@ -23,6 +23,7 @@ import org.jetbrains.idea.svn.api.BaseSvnClient; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; import org.tmatesoft.svn.core.wc.SVNLogClient; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -38,7 +39,7 @@ public class SvnKitBrowseClient extends BaseSvnClient implements BrowseClient { @Nullable DirectoryEntryConsumer handler) throws VcsException { assertUrl(target); - SVNLogClient client = myVcs.getSvnKitManager().createLogClient(); + SVNLogClient client = getLogClient(); ISVNDirEntryHandler wrappedHandler = wrapHandler(handler); try { @@ -69,6 +70,15 @@ public class SvnKitBrowseClient extends BaseSvnClient implements BrowseClient { } } + @NotNull + private SVNLogClient getLogClient() { + ISVNAuthenticationManager authManager = myIsActive + ? myVcs.getSvnConfiguration().getInteractiveManager(myVcs) + : myVcs.getSvnConfiguration().getPassiveAuthenticationManager(myVcs.getProject()); + + return myVcs.getSvnKitManager().createLogClient(authManager); + } + @Nullable private static ISVNDirEntryHandler wrapHandler(@Nullable DirectoryEntryConsumer handler) { return handler == null ? null : new SkipEmptyNameDirectoriesHandler(handler); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthCallbackCase.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthCallbackCase.java index 8a55a6e89860..77cca02a04fb 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthCallbackCase.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthCallbackCase.java @@ -16,6 +16,7 @@ package org.jetbrains.idea.svn.commandLine; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.auth.AuthenticationService; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; @@ -25,10 +26,10 @@ import org.tmatesoft.svn.core.SVNURL; public abstract class AuthCallbackCase { protected final SVNURL myUrl; protected boolean myTried = false; - @NotNull protected final AuthenticationCallback myAuthenticationCallback; + @NotNull protected final AuthenticationService myAuthenticationService; - AuthCallbackCase(@NotNull AuthenticationCallback callback, SVNURL url) { - myAuthenticationCallback = callback; + AuthCallbackCase(@NotNull AuthenticationService authenticationService, SVNURL url) { + myAuthenticationService = authenticationService; myUrl = url; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthenticationCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthenticationCallback.java deleted file mode 100644 index 11fb831803bb..000000000000 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/AuthenticationCallback.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2000-2013 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.svn.commandLine; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.dialogs.SimpleCredentialsDialog; -import org.tmatesoft.svn.core.SVNURL; -import org.tmatesoft.svn.core.auth.SVNAuthentication; - -import java.io.File; -import java.net.PasswordAuthentication; - -/** - * Passed for authentication purpose to SvnLineCommand - * Called when svn command indicates that it needs credentials. It also means that credential was not found in standard place - * (Subversion config directory) - * - * Implementations should 1) ask credential from user or take it from any other storage (memory, for instance) - * 2) write credential in Subversion standard form into - * a) standard config directory if user allowed to save *all* credentials - * b) TMP directory and return path to the directory from getSpecialConfigDir() - if user rejected at least one credential storing - * - * Please note that several credentials could be asked during the command and therefore implementation class is used as - * keeping its state, and that TMP directory should be reused for all written credentials - * - * User: Irina.Chernushina - * Date: 2/26/13 - * Time: 1:05 PM - */ -public interface AuthenticationCallback { - /** - * Authenticate for realm and base file belonging to corresponding working copy - * - * @param realm - realm that should be used for credential retrieval/storage. - * @param repositoryUrl - * @param previousFailed - whether previous credentials were correct - * @param passwordRequest - if true, password should be asked. Otherwise that may be a certificate (determined by the protocol) - * @return false if authentication canceled or was unsuccessful - */ - boolean authenticateFor(@Nullable String realm, SVNURL repositoryUrl, boolean previousFailed, boolean passwordRequest); - - /** - * Provides authentication information to access given url by authentication protocol identified by type. - * For instance, username/password for http/svn protocols. SSL client certificate for two way SSL protocol. - * - * @param repositoryUrl - * @param type authentication protocol type with svn specific values, like "svn.simple" for http. - * @return - */ - @Nullable - SVNAuthentication requestCredentials(SVNURL repositoryUrl, String type); - - /** - * @return config directory if TMP was created - */ - @Nullable - File getSpecialConfigDir(); - - @Nullable - String requestSshCredentials(@NotNull String realm, - @NotNull SimpleCredentialsDialog.Mode mode, - @NotNull String key); - - /** - * Ask user or read from memory storage whether server certificate should be accepted - * - * @param repositoryUrl - * @param realm - realm that should be used for credential retrieval/storage. - * @return true is certificate was accepted - */ - boolean acceptSSLServerCertificate(SVNURL repositoryUrl, final String realm); - - /** - * Clear credentials stored anywhere - in case they were not full, wrong or anything else - * - * @param realm - required that credential - * @param repositoryUrl - * @param password - whether password credential should be deleted or certificate, if protocol might demand certificate - */ - void clearPassiveCredentials(String realm, SVNURL repositoryUrl, boolean password); - - /** - * @return true if there's something from IDEA config that should be persisted into Subversion tmp config directory - * for successful call - * (now it's IDEA proxy settings) - */ - boolean haveDataForTmpConfig(); - - @Nullable - PasswordAuthentication getProxyAuthentication(@NotNull SVNURL repositoryUrl); - - void reset(); -} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseCommandRuntimeModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseCommandRuntimeModule.java index 1b4235d8ffcf..86a27fa393b7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseCommandRuntimeModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseCommandRuntimeModule.java @@ -17,6 +17,7 @@ package org.jetbrains.idea.svn.commandLine; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.auth.AuthenticationService; /** * @author Konstantin Kolosovsky. @@ -24,12 +25,12 @@ import org.jetbrains.idea.svn.SvnVcs; public abstract class BaseCommandRuntimeModule implements CommandRuntimeModule { @NotNull protected final CommandRuntime myRuntime; - @NotNull protected final AuthenticationCallback myAuthCallback; + @NotNull protected final AuthenticationService myAuthenticationService; @NotNull protected final SvnVcs myVcs; public BaseCommandRuntimeModule(@NotNull CommandRuntime runtime) { myRuntime = runtime; - myAuthCallback = runtime.getAuthCallback(); + myAuthenticationService = runtime.getAuthenticationService(); myVcs = runtime.getVcs(); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CertificateCallbackCase.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CertificateCallbackCase.java index a63d4544a5f5..f58a775079ed 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CertificateCallbackCase.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CertificateCallbackCase.java @@ -17,6 +17,7 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.auth.AuthenticationService; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; @@ -31,8 +32,8 @@ public class CertificateCallbackCase extends AuthCallbackCase { private boolean accepted; - CertificateCallbackCase(@NotNull AuthenticationCallback callback, SVNURL url) { - super(callback, url); + CertificateCallbackCase(@NotNull AuthenticationService authenticationService, SVNURL url) { + super(authenticationService, url); } @Override @@ -55,7 +56,7 @@ public class CertificateCallbackCase extends AuthCallbackCase { realm = serverUrl != null ? serverUrl.toString() : realm; } - if (!myTried && myAuthenticationCallback.acceptSSLServerCertificate(myUrl, realm)) { + if (!myTried && myAuthenticationService.acceptSSLServerCertificate(myUrl, realm)) { accepted = true; myTried = true; return true; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandParametersResolutionModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandParametersResolutionModule.java index e4883549b0aa..e86fdf388a7f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandParametersResolutionModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandParametersResolutionModule.java @@ -43,7 +43,7 @@ public class CommandParametersResolutionModule extends BaseCommandRuntimeModule if (command.getWorkingDirectory() == null) { command.setWorkingDirectory(resolveWorkingDirectory(command)); } - command.setConfigDir(myAuthCallback.getSpecialConfigDir()); + command.setConfigDir(myAuthenticationService.getSpecialConfigDir()); command.saveOriginalParameters(); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java index 5cc66e0a3983..4902891163d6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java @@ -24,6 +24,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.auth.AuthenticationService; import org.jetbrains.idea.svn.auth.SvnAuthenticationManager; import org.tmatesoft.svn.core.SVNURL; @@ -37,14 +38,14 @@ public class CommandRuntime { private static final Logger LOG = Logger.getInstance(CommandRuntime.class); - @NotNull private final AuthenticationCallback myAuthCallback; + @NotNull private final AuthenticationService myAuthenticationService; @NotNull private final SvnVcs myVcs; @NotNull private final List<CommandRuntimeModule> myModules; private final String exePath; - public CommandRuntime(@NotNull SvnVcs vcs, @NotNull AuthenticationCallback authCallback) { + public CommandRuntime(@NotNull SvnVcs vcs, @NotNull AuthenticationService authenticationService) { myVcs = vcs; - myAuthCallback = authCallback; + myAuthenticationService = authenticationService; exePath = SvnApplicationSettings.getInstance().getCommandLinePath(); myModules = ContainerUtil.newArrayList(); @@ -130,8 +131,8 @@ public class CommandRuntime { // "infinite" times despite it was cancelled. if (!executor.checkCancelled() && callback != null) { if (callback.getCredentials(errText)) { - if (myAuthCallback.getSpecialConfigDir() != null) { - command.setConfigDir(myAuthCallback.getSpecialConfigDir()); + if (myAuthenticationService.getSpecialConfigDir() != null) { + command.setConfigDir(myAuthenticationService.getSpecialConfigDir()); } callback.updateParameters(command); return true; @@ -153,7 +154,7 @@ public class CommandRuntime { } private void onFinish() { - myAuthCallback.reset(); + myAuthenticationService.reset(); } private static void logNullExitCode(@NotNull CommandExecutor executor, @Nullable Integer exitCode) { @@ -166,12 +167,12 @@ public class CommandRuntime { private AuthCallbackCase createCallback(@NotNull final String errText, @Nullable final SVNURL url) { List<AuthCallbackCase> authCases = ContainerUtil.newArrayList(); - authCases.add(new CertificateCallbackCase(myAuthCallback, url)); - authCases.add(new CredentialsCallback(myAuthCallback, url)); - authCases.add(new PassphraseCallback(myAuthCallback, url)); - authCases.add(new ProxyCallback(myAuthCallback, url)); - authCases.add(new TwoWaySslCallback(myAuthCallback, url)); - authCases.add(new UsernamePasswordCallback(myAuthCallback, url)); + authCases.add(new CertificateCallbackCase(myAuthenticationService, url)); + authCases.add(new CredentialsCallback(myAuthenticationService, url)); + authCases.add(new PassphraseCallback(myAuthenticationService, url)); + authCases.add(new ProxyCallback(myAuthenticationService, url)); + authCases.add(new TwoWaySslCallback(myAuthenticationService, url)); + authCases.add(new UsernamePasswordCallback(myAuthenticationService, url)); return ContainerUtil.find(authCases, new Condition<AuthCallbackCase>() { @Override @@ -242,8 +243,8 @@ public class CommandRuntime { } @NotNull - public AuthenticationCallback getAuthCallback() { - return myAuthCallback; + public AuthenticationService getAuthenticationService() { + return myAuthenticationService; } @NotNull diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CredentialsCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CredentialsCallback.java index 15f3a78aff5d..5304dff13e01 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CredentialsCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CredentialsCallback.java @@ -17,6 +17,7 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.auth.AuthenticationService; import org.tmatesoft.svn.core.SVNURL; /** @@ -26,8 +27,8 @@ public class CredentialsCallback extends AuthCallbackCase { private static final String AUTHENTICATION_REALM = "Authentication realm:"; - CredentialsCallback(@NotNull AuthenticationCallback callback, SVNURL url) { - super(callback, url); + CredentialsCallback(@NotNull AuthenticationService authenticationService, SVNURL url) { + super(authenticationService, url); } @Override @@ -43,10 +44,10 @@ public class CredentialsCallback extends AuthCallbackCase { : null; final boolean isPassword = StringUtil.containsIgnoreCase(errText, "password"); if (myTried) { - myAuthenticationCallback.clearPassiveCredentials(realm, myUrl, isPassword); + myAuthenticationService.clearPassiveCredentials(realm, myUrl, isPassword); } myTried = true; - if (myAuthenticationCallback.authenticateFor(realm, myUrl, myAuthenticationCallback.getSpecialConfigDir() != null, isPassword)) { + if (myAuthenticationService.authenticateFor(realm, myUrl, isPassword)) { return true; } throw new SvnBindException("Authentication canceled for realm: " + realm); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/PassphraseCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/PassphraseCallback.java index 70e3d245329b..fe793c05fb31 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/PassphraseCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/PassphraseCallback.java @@ -16,6 +16,7 @@ package org.jetbrains.idea.svn.commandLine; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.auth.AuthenticationService; import org.tmatesoft.svn.core.SVNURL; /** @@ -25,8 +26,8 @@ public class PassphraseCallback extends AuthCallbackCase { private static final String PASSPHRASE_FOR = "Passphrase for"; - PassphraseCallback(@NotNull AuthenticationCallback callback, SVNURL url) { - super(callback, url); + PassphraseCallback(@NotNull AuthenticationService authenticationService, SVNURL url) { + super(authenticationService, url); } @Override @@ -38,10 +39,10 @@ public class PassphraseCallback extends AuthCallbackCase { boolean getCredentials(String errText) throws SvnBindException { // try to get from file /*if (myTried) { - myAuthenticationCallback.clearPassiveCredentials(null, myBase); + myAuthenticationService.clearPassiveCredentials(null, myBase); }*/ myTried = true; - if (myAuthenticationCallback.authenticateFor(null, myUrl, myAuthenticationCallback.getSpecialConfigDir() != null, false)) { + if (myAuthenticationService.authenticateFor(null, myUrl, false)) { return true; } throw new SvnBindException("Authentication canceled for : " + errText.substring(PASSPHRASE_FOR.length())); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyCallback.java index 340100dcb3a6..a3afaf9a5c0c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyCallback.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.auth.AuthenticationService; import org.tmatesoft.svn.core.SVNURL; import java.net.PasswordAuthentication; @@ -36,8 +37,8 @@ public class ProxyCallback extends AuthCallbackCase { private PasswordAuthentication myProxyAuthentication; - ProxyCallback(@NotNull AuthenticationCallback callback, SVNURL url) { - super(callback, url); + ProxyCallback(@NotNull AuthenticationService authenticationService, SVNURL url) { + super(authenticationService, url); } @Override @@ -61,8 +62,8 @@ public class ProxyCallback extends AuthCallbackCase { result = true; // explicit check if proxies are configured in IDEA is used here not to perform "proxy authentication" for proxies manually // specified by users in svn "servers" file - } else if (myAuthenticationCallback.haveDataForTmpConfig()) { - myProxyAuthentication = myAuthenticationCallback.getProxyAuthentication(myUrl); + } else if (myAuthenticationService.haveDataForTmpConfig()) { + myProxyAuthentication = myAuthenticationService.getProxyAuthentication(myUrl); result = myProxyAuthentication != null; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyModule.java index 11bb9b654523..bdfdd55ed6e1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyModule.java @@ -19,8 +19,8 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.IdeaSVNConfigFile; +import org.jetbrains.idea.svn.auth.AuthenticationService; import org.jetbrains.idea.svn.auth.SvnAuthenticationManager; -import org.jetbrains.idea.svn.auth.IdeaSvnkitBasedAuthenticationCallback; import org.tmatesoft.svn.core.SVNURL; import java.net.InetSocketAddress; @@ -39,7 +39,7 @@ public class ProxyModule extends BaseCommandRuntimeModule { @Override public void onStart(@NotNull Command command) throws SvnBindException { - if (myAuthCallback.haveDataForTmpConfig()) { + if (myAuthenticationService.haveDataForTmpConfig()) { setupProxy(command); } } @@ -50,7 +50,7 @@ public class ProxyModule extends BaseCommandRuntimeModule { SVNURL repositoryUrl = command.getRepositoryUrl(); if (repositoryUrl != null) { - Proxy proxy = IdeaSvnkitBasedAuthenticationCallback.getIdeaDefinedProxy(repositoryUrl); + Proxy proxy = AuthenticationService.getIdeaDefinedProxy(repositoryUrl); if (proxy != null) { String hostGroup = ensureGroupForHost(command, repositoryUrl.getHost()); @@ -68,7 +68,7 @@ public class ProxyModule extends BaseCommandRuntimeModule { @NotNull private String ensureGroupForHost(@NotNull Command command, @NotNull String host) { - IdeaSVNConfigFile configFile = new IdeaSVNConfigFile(myAuthCallback.getSpecialConfigDir()); + IdeaSVNConfigFile configFile = new IdeaSVNConfigFile(myAuthenticationService.getSpecialConfigDir()); String groupName = SvnAuthenticationManager.getGroupForHost(host, configFile); if (StringUtil.isEmptyOrSpaces(groupName)) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java index 6694083b4d81..f4b4f0d4b0fc 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnBindException.java @@ -21,6 +21,7 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnUtil; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; @@ -52,18 +53,22 @@ public class SvnBindException extends VcsException { errors.putValue(code.getCode(), getMessage()); } - public SvnBindException(String message) { - super(message); + public SvnBindException(@Nullable String message) { + this(message, null); + } - if (!StringUtil.isEmpty(message)) { - parse(message, SvnUtil.ERROR_PATTERN, errors); - parse(message, SvnUtil.WARNING_PATTERN, warnings); - } + public SvnBindException(@Nullable Throwable cause) { + this(null, cause); } - public SvnBindException(Throwable throwable) { - super(throwable); + public SvnBindException(@Nullable String message, @Nullable Throwable cause) { + super(message, cause); + + init(message); + init(cause); + } + private void init(@Nullable Throwable throwable) { if (throwable instanceof SVNException) { SVNException e = (SVNException)throwable; int code = e.getErrorMessage().getErrorCode().getCode(); @@ -73,6 +78,13 @@ public class SvnBindException extends VcsException { } } + private void init(@Nullable String message) { + if (!StringUtil.isEmpty(message)) { + parse(message, SvnUtil.ERROR_PATTERN, errors); + parse(message, SvnUtil.WARNING_PATTERN, warnings); + } + } + public boolean contains(int code) { return errors.containsKey(code) || warnings.containsKey(code); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnExecutableChecker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnExecutableChecker.java index 4a5183ac5e4c..1add2022074a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnExecutableChecker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnExecutableChecker.java @@ -26,6 +26,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnApplicationSettings; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.WorkingCopyFormat; /** * Created with IntelliJ IDEA. @@ -82,7 +83,7 @@ public class SvnExecutableChecker extends ExecutableValidator { } private boolean validateVersion(@NotNull Version version) { - if (version.lessThan(1, 7)) { + if (!getVcs().isSupportedByCommandLine(WorkingCopyFormat.from(version))) { setNotificationErrorDescription(getOldExecutableMessage(version)); return false; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java index 5a624e9d3414..ca4fce9d910b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java @@ -130,7 +130,7 @@ public class TerminalSshModule extends LineCommandAdapter implements CommandRunt // TODO: authentication (like "svn info <file> -r HEAD"), if it is invoked before all working copy roots are resolved. // TODO: resolving repositoryUrl logic should be updated so that repositoryUrl is not null here. String auth = - myRuntime.getAuthCallback().requestSshCredentials(repositoryUrl != null ? repositoryUrl.toDecodedString() : "", mode, key); + myRuntime.getAuthenticationService().requestSshCredentials(repositoryUrl != null ? repositoryUrl.toDecodedString() : "", mode, key); if (!StringUtil.isEmpty(auth)) { sendAnswer(auth); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TwoWaySslCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TwoWaySslCallback.java index e9df472b65c2..fe8ad9208e5f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TwoWaySslCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TwoWaySslCallback.java @@ -16,6 +16,7 @@ package org.jetbrains.idea.svn.commandLine; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.auth.AuthenticationService; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; import org.tmatesoft.svn.core.auth.SVNSSLAuthentication; @@ -28,8 +29,8 @@ public class TwoWaySslCallback extends UsernamePasswordCallback { private static final String ACCESS_TO_PREFIX = "Access to "; private static final String FORBIDDEN_STATUS = "forbidden"; - TwoWaySslCallback(AuthenticationCallback callback, SVNURL url) { - super(callback, url); + TwoWaySslCallback(@NotNull AuthenticationService authenticationService, SVNURL url) { + super(authenticationService, url); } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UsernamePasswordCallback.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UsernamePasswordCallback.java index caeb92f1d734..ad908b213ab3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UsernamePasswordCallback.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UsernamePasswordCallback.java @@ -15,7 +15,9 @@ */ package org.jetbrains.idea.svn.commandLine; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.auth.AuthenticationService; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; import org.tmatesoft.svn.core.auth.SVNAuthentication; @@ -32,6 +34,7 @@ import java.util.regex.Pattern; */ public class UsernamePasswordCallback extends AuthCallbackCase { + private static final String COULD_NOT_AUTHENTICATE_TO_SERVER_MESSAGE = "could not authenticate to server"; private static final String UNABLE_TO_CONNECT_MESSAGE = "Unable to connect to a repository"; private static final String AUTHENTICATION_FAILED_MESSAGE = "Authentication failed"; private static final String INVALID_CREDENTIALS_FOR_SVN_PROTOCOL = "svn: E170001: Can't get"; @@ -40,8 +43,8 @@ public class UsernamePasswordCallback extends AuthCallbackCase { protected SVNAuthentication myAuthentication; - UsernamePasswordCallback(@NotNull AuthenticationCallback callback, SVNURL url) { - super(callback, url); + UsernamePasswordCallback(@NotNull AuthenticationService authenticationService, SVNURL url) { + super(authenticationService, url); } @Override @@ -52,13 +55,14 @@ public class UsernamePasswordCallback extends AuthCallbackCase { // svn protocol invalid credentials - messages could be "Can't get password", "Can't get username or password" error.contains(INVALID_CREDENTIALS_FOR_SVN_PROTOCOL) && error.contains(PASSWORD_STRING) || // http/https protocol, svn 1.7, non-interactive - error.contains(UNABLE_TO_CONNECT_MESSAGE); + error.contains(UNABLE_TO_CONNECT_MESSAGE) || + // http, svn 1.6, non-interactive + StringUtil.containsIgnoreCase(error, COULD_NOT_AUTHENTICATE_TO_SERVER_MESSAGE); } @Override boolean getCredentials(String errText) throws SvnBindException { - myAuthentication = myAuthenticationCallback.requestCredentials(myUrl != null ? myUrl : parseUrlFromError(errText), - getType()); + myAuthentication = myAuthenticationService.requestCredentials(myUrl != null ? myUrl : parseUrlFromError(errText), getType()); return myAuthentication != null; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/CmdUpdateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/CmdUpdateClient.java index 61b0592af085..8406f1ecec5b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/CmdUpdateClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/CmdUpdateClient.java @@ -18,6 +18,7 @@ package org.jetbrains.idea.svn.update; import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.WorkingCopyFormat; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.api.EventAction; import org.jetbrains.idea.svn.api.ProgressEvent; @@ -26,7 +27,10 @@ import org.jetbrains.idea.svn.commandLine.CommandUtil; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.jetbrains.idea.svn.commandLine.SvnCommandName; import org.jetbrains.idea.svn.info.Info; -import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.SVNErrorCode; +import org.tmatesoft.svn.core.SVNErrorMessage; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -163,7 +167,10 @@ public class CmdUpdateClient extends SvnKitUpdateClient { CommandUtil.put(parameters, SvnTarget.fromURL(url, pegRevision)); CommandUtil.put(parameters, path, false); fillParameters(parameters, revision, depth, depthIsSticky, allowUnversionedObstructions); - parameters.add("--ignore-ancestry"); + if (!myVcs.is16SupportedByCommandLine() || + WorkingCopyFormat.from(myFactory.createVersionClient().getVersion()).isOrGreater(WorkingCopyFormat.ONE_DOT_SEVEN)) { + parameters.add("--ignore-ancestry"); + } long[] revisions = run(path, parameters, SvnCommandName.switchCopy); diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCachingRepositoryPoolTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCachingRepositoryPoolTest.java index e2475e020950..ecad58e2b20d 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCachingRepositoryPoolTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCachingRepositoryPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 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. @@ -107,13 +107,7 @@ public class SvnCachingRepositoryPoolTest extends FileBasedTest { } } }; - final EmptyProgressIndicator indicator = new EmptyProgressIndicator() { - @Override - public void cancel() { - super.cancel(); - ProgressManagerImpl.canceled(); - } - }; + final EmptyProgressIndicator indicator = new EmptyProgressIndicator(); Thread thread = new Thread(new Runnable() { @Override public void run() { diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCommandLineStabilityTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCommandLineStabilityTest.java index 76cc3c8ce9af..4918ef06eb39 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCommandLineStabilityTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnCommandLineStabilityTest.java @@ -1,16 +1,15 @@ package org.jetbrains.idea.svn; import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VfsUtilCore; import junit.framework.Assert; -import org.jetbrains.idea.svn.api.BaseSvnClient; -import org.jetbrains.idea.svn.commandLine.CommandExecutor; -import org.jetbrains.idea.svn.commandLine.SvnCommandName; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.auth.AuthenticationService; +import org.jetbrains.idea.svn.commandLine.*; import org.junit.Test; import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; -import java.util.ArrayList; -import java.util.List; /** * Created with IntelliJ IDEA. @@ -30,15 +29,22 @@ public class SvnCommandLineStabilityTest extends Svn17TestCase { } private void call() throws VcsException { - List<String> parameters = new ArrayList<String>(); - parameters.add("--xml"); - - SvnVcs vcs = SvnVcs.getInstance(myProject); - File workingDirectory = new File(myWorkingCopyDir.getPath()); - CommandExecutor command = - BaseSvnClient.execute(vcs, SvnTarget.fromFile(workingDirectory), workingDirectory, SvnCommandName.info, parameters, null); - final String result = command.getOutput(); + String result = runInfo().getOutput(); System.out.println(result); Assert.assertNotNull(result); } + + @NotNull + private CommandExecutor runInfo() throws SvnBindException { + SvnVcs vcs = SvnVcs.getInstance(myProject); + File workingDirectory = VfsUtilCore.virtualToIoFile(myWorkingCopyDir); + Command command = new Command(SvnCommandName.info); + + command.setTarget(SvnTarget.fromFile(workingDirectory)); + command.setWorkingDirectory(workingDirectory); + command.put("--xml"); + + CommandRuntime runtime = new CommandRuntime(vcs, new AuthenticationService(vcs, true)); + return runtime.runWithAuthenticationAttempt(command); + } } diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepositoryImpl.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepositoryImpl.java index 30ecaf19f2da..ef3d88158f4d 100644 --- a/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepositoryImpl.java +++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepositoryImpl.java @@ -1,7 +1,6 @@ package com.intellij.tasks.impl; import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.tasks.TaskRepositoryType; import com.intellij.tasks.config.TaskSettings; import com.intellij.util.net.HttpConfigurable; @@ -20,7 +19,6 @@ import java.net.URLEncoder; * @author Dmitry Avdeev */ public abstract class BaseRepositoryImpl extends BaseRepository { - private static final Logger LOG = Logger.getInstance(BaseRepositoryImpl.class); private final HttpClient myClient; protected BaseRepositoryImpl() { @@ -113,8 +111,7 @@ public abstract class BaseRepositoryImpl extends BaseRepository { protected void configureHttpMethod(HttpMethod method) { } - public abstract class HttpTestConnection<T extends HttpMethod> extends CancellableConnection { - + public abstract static class HttpTestConnection<T extends HttpMethod> extends CancellableConnection { protected T myMethod; public HttpTestConnection(T method) { diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java index 6fe1467b1b47..2cc241e4d8a1 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java @@ -28,7 +28,6 @@ import com.intellij.openapi.ui.ValidationInfo; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.VcsTaskHandler; -import com.intellij.openapi.vcs.VcsType; import com.intellij.tasks.*; import com.intellij.tasks.impl.TaskManagerImpl; import com.intellij.tasks.impl.TaskUtil; @@ -106,7 +105,8 @@ public class OpenTaskDialog extends DialogWrapper { myCreateBranch.addActionListener(listener); myCreateChangelist.setSelected(manager.getState().createChangelist); - if (vcs.getType() != VcsType.distributed) { + VcsTaskHandler[] handlers = VcsTaskHandler.getAllHandlers(project); + if (handlers.length == 0) { myCreateBranch.setSelected(false); myCreateBranch.setVisible(false); myBranchName.setVisible(false); @@ -114,7 +114,6 @@ public class OpenTaskDialog extends DialogWrapper { myBranchFrom.setVisible(false); } else { - VcsTaskHandler[] handlers = VcsTaskHandler.getAllHandlers(project); for (VcsTaskHandler handler : handlers) { VcsTaskHandler.TaskInfo[] tasks = handler.getCurrentTasks(); if (tasks.length > 0) { diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java index 8f14564c74b5..c1648fc8f490 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java @@ -1,6 +1,5 @@ package com.intellij.tasks.impl.httpclient; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.tasks.TaskRepositoryType; import com.intellij.tasks.config.TaskSettings; import com.intellij.tasks.impl.BaseRepository; @@ -34,7 +33,6 @@ import java.io.IOException; * @author Mikhail Golubev */ public abstract class NewBaseRepositoryImpl extends BaseRepository { - private static final Logger LOG = Logger.getInstance(NewBaseRepositoryImpl.class); private static final AuthScope BASIC_AUTH_SCOPE = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.BASIC); // Provides preemptive authentication in HttpClient 4.x diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/vcs/TaskVcsTest.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/vcs/TaskVcsTest.java index d78c5c055b47..c08230becf46 100644 --- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/vcs/TaskVcsTest.java +++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/vcs/TaskVcsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 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. @@ -493,6 +493,7 @@ public class TaskVcsTest extends CodeInsightFixtureTestCase { finally { myTaskManager = null; myVcs = null; + myChangeListManager = null; } super.tearDown(); } diff --git a/plugins/terminal/resources/META-INF/terminal.xml b/plugins/terminal/resources/META-INF/terminal.xml index e85297f2b715..b41877f9db87 100644 --- a/plugins/terminal/resources/META-INF/terminal.xml +++ b/plugins/terminal/resources/META-INF/terminal.xml @@ -3,7 +3,7 @@ <toolWindow id="Terminal" anchor="bottom" icon="TerminalIcons.OpenTerminal_13x13" factoryClass="org.jetbrains.plugins.terminal.TerminalToolWindowFactory" secondary="false"/> - <projectConfigurable groupId="tools" displayName="Terminal" instance="org.jetbrains.plugins.terminal.TerminalOptionsConfigurable"/> + <projectConfigurable groupId="tools" groupWeight="130" displayName="Terminal" instance="org.jetbrains.plugins.terminal.TerminalOptionsConfigurable"/> <fileEditorProvider implementation="org.jetbrains.plugins.terminal.vfs.TerminalSessionEditorProvider"/> </extensions> diff --git a/plugins/testng/src/META-INF/plugin.xml b/plugins/testng/src/META-INF/plugin.xml index fff400d9f794..5fe0fb55b60f 100644 --- a/plugins/testng/src/META-INF/plugin.xml +++ b/plugins/testng/src/META-INF/plugin.xml @@ -46,6 +46,9 @@ <localInspection language="JAVA" shortName="MisorderedAssertEqualsArgumentsTestNG" displayName="Misordered 'assertEquals()' arguments" groupName="TestNG" enabledByDefault="false" level="WARNING" implementationClass="com.theoryinpractice.testng.inspection.MisorderedAssertEqualsArgumentsTestNGInspection"/> + <localInspection language="JAVA" shortName="TestNGMethodNamingConvention" displayName="TestNG test method naming convention" + groupName="TestNG" enabledByDefault="false" level="WARNING" + implementationClass="com.theoryinpractice.testng.inspection.TestNGMethodNamingConventionInspection"/> <intentionAction> <className>com.theoryinpractice.testng.intention.TestNGOrderEntryFix</className> diff --git a/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java b/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java index 0a9acf231499..6e483fb97c3d 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java +++ b/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java @@ -170,7 +170,7 @@ public class TestNGReferenceContributor extends PsiReferenceContributor { if (cls != null) { PsiMethod[] methods = cls.findMethodsByName(methodName, true); for (PsiMethod method : methods) { - if (TestNGUtil.hasTest(method) || TestNGUtil.hasConfig(method)) { + if (TestNGUtil.hasTest(method, false) || TestNGUtil.hasConfig(method)) { return method; } } diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java index 413aceebf8d4..2258b16a7a2a 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java @@ -191,11 +191,22 @@ public class SearchingForTestsTask extends Task.Backgroundable { private void composeTestSuiteFromClasses() { Map<String, Collection<String>> map = new HashMap<String, Collection<String>>(); + + final boolean findTestMethodsForClass = shouldSearchForTestMethods(); + for (final Map.Entry<PsiClass, Collection<PsiMethod>> entry : myClasses.entrySet()) { - Collection<String> methods = new HashSet<String>(entry.getValue().size()); - for (PsiMethod method : entry.getValue()) { + final Collection<PsiMethod> depMethods = entry.getValue(); + Collection<String> methods = new HashSet<String>(depMethods.size()); + for (PsiMethod method : depMethods) { methods.add(method.getName()); } + if (findTestMethodsForClass && depMethods.isEmpty()) { + for (PsiMethod method : entry.getKey().getMethods()) { + if (TestNGUtil.hasTest(method)) { + methods.add(method.getName()); + } + } + } map.put(ApplicationManager.getApplication().runReadAction( new Computable<String>() { @Nullable @@ -243,6 +254,17 @@ public class SearchingForTestsTask extends Task.Backgroundable { } } + private boolean shouldSearchForTestMethods() { + boolean dependantMethods = false; + for (Collection<PsiMethod> methods : myClasses.values()) { + if (!methods.isEmpty()) { + dependantMethods = true; + break; + } + } + return dependantMethods; + } + private void composeTestSuiteFromXml() throws CantRunException { final Map<String, String> buildTestParams = buildTestParameters(); try { diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java index 21afb568e912..0c73ae5f5761 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java @@ -144,19 +144,6 @@ public class TestNGRunnableState extends JavaCommandLineState { if (mySearchForTestIndicator != null && !mySearchForTestIndicator.isCanceled()) { task.finish(); } - - final Runnable notificationRunnable = new Runnable() { - public void run() { - final Project project = config.getProject(); - if (project.isDisposed()) return; - - final TestConsoleProperties consoleProperties = console.getProperties(); - if (consoleProperties == null) return; - final TestNGResults resultsView = console.getResultsView(); - TestsUIUtil.notifyByBalloon(project, myStarted, console.getResultsView().getRoot(), consoleProperties, "in " + resultsView.getTime()); - } - }; - SwingUtilities.invokeLater(notificationRunnable); } @Override @@ -175,7 +162,7 @@ public class TestNGRunnableState extends JavaCommandLineState { public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) { final TestNGResults resultsView = console.getResultsView(); if (resultsView != null) { - resultsView.finish(); + resultsView.finish(myStarted); } } diff --git a/plugins/testng/src/com/theoryinpractice/testng/inspection/DependsOnMethodInspection.java b/plugins/testng/src/com/theoryinpractice/testng/inspection/DependsOnMethodInspection.java index b8cf78a83d5d..aeda466432a2 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/inspection/DependsOnMethodInspection.java +++ b/plugins/testng/src/com/theoryinpractice/testng/inspection/DependsOnMethodInspection.java @@ -18,14 +18,19 @@ package com.theoryinpractice.testng.inspection; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInspection.*; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashSet; import com.theoryinpractice.testng.util.TestNGUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -35,7 +40,7 @@ import java.util.regex.Pattern; public class DependsOnMethodInspection extends BaseJavaLocalInspectionTool { private static final Logger LOGGER = Logger.getInstance("TestNG Runner"); - private static final Pattern PATTERN = Pattern.compile("\"([a-zA-Z1-9_\\(\\)]*)\""); + private static final Pattern PATTERN = Pattern.compile("\"([a-zA-Z1-9_\\(\\)\\*]*)\""); @NotNull @Override @@ -63,17 +68,13 @@ public class DependsOnMethodInspection extends BaseJavaLocalInspectionTool @Nullable public ProblemDescriptor[] checkClass(@NotNull PsiClass psiClass, @NotNull InspectionManager manager, boolean isOnTheFly) { - //LOGGER.info("Looking for dependsOnMethods problems in " + psiClass.getName()); - - if (!psiClass.getContainingFile().isWritable()) return null; - PsiAnnotation[] annotations = TestNGUtil.getTestNGAnnotations(psiClass); if(annotations.length == 0) return ProblemDescriptor.EMPTY_ARRAY; List<ProblemDescriptor> problemDescriptors = new ArrayList<ProblemDescriptor>(); for (PsiAnnotation annotation : annotations) { final PsiAnnotationMemberValue value = annotation.findDeclaredAttributeValue("dependsOnMethods"); - if (value != null) { + if (value != null && !TestNGUtil.isDisabled(annotation)) { String text = value.getText(); if (value instanceof PsiReferenceExpression) { final PsiElement resolve = ((PsiReferenceExpression)value).resolve(); @@ -84,10 +85,25 @@ public class DependsOnMethodInspection extends BaseJavaLocalInspectionTool } } } - Matcher matcher = PATTERN.matcher(text); + final Set<String> names = new HashSet<String>(); + final Matcher matcher = PATTERN.matcher(text); + int idx = 0; while (matcher.find()) { - String methodName = matcher.group(1); + String methodName = matcher.group(1); + if (!names.add(methodName)) { + PsiAnnotationMemberValue element2Highlight = value; + if (value instanceof PsiArrayInitializerMemberValue) { + final PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)value).getInitializers(); + if (idx < initializers.length) { + element2Highlight = initializers[idx]; + } + } + problemDescriptors.add(manager.createProblemDescriptor(element2Highlight, "Duplicated method name: " + methodName, + (LocalQuickFix)null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + isOnTheFly)); + } checkMethodNameDependency(manager, psiClass, methodName, value, problemDescriptors, isOnTheFly); + idx++; } } } @@ -111,7 +127,19 @@ public class DependsOnMethodInspection extends BaseJavaLocalInspectionTool } else { final String configAnnotation = TestNGUtil.getConfigAnnotation(PsiTreeUtil.getParentOfType(value, PsiMethod.class)); - PsiMethod[] foundMethods = psiClass.findMethodsByName(methodName, true); + final PsiMethod[] foundMethods; + if (methodName.endsWith("*")) { + final String methodNameMask = StringUtil.trimEnd(methodName, "*"); + final List<PsiMethod> methods = ContainerUtil.filter(psiClass.getMethods(), new Condition<PsiMethod>() { + @Override + public boolean value(PsiMethod method) { + return method.getName().startsWith(methodNameMask); + } + }); + foundMethods = methods.toArray(new PsiMethod[methods.size()]); + } else { + foundMethods = psiClass.findMethodsByName(methodName, true); + } if (foundMethods.length == 0) { LOGGER.debug("dependsOnMethods method doesn't exist:" + methodName); ProblemDescriptor descriptor = manager.createProblemDescriptor(value, diff --git a/plugins/testng/src/com/theoryinpractice/testng/inspection/TestNGMethodNamingConventionInspection.java b/plugins/testng/src/com/theoryinpractice/testng/inspection/TestNGMethodNamingConventionInspection.java new file mode 100644 index 000000000000..2cc894faf064 --- /dev/null +++ b/plugins/testng/src/com/theoryinpractice/testng/inspection/TestNGMethodNamingConventionInspection.java @@ -0,0 +1,105 @@ +/* + * 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.theoryinpractice.testng.inspection; + +import com.intellij.psi.PsiIdentifier; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.naming.ConventionInspection; +import com.siyeh.ig.psiutils.LibraryUtil; +import com.siyeh.ig.psiutils.MethodUtils; +import com.theoryinpractice.testng.util.TestNGUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Bas Leijdekkers + */ +public class TestNGMethodNamingConventionInspection extends ConventionInspection { + @Nls + @NotNull + @Override + public String getDisplayName() { + return "TestNG test method naming convention"; + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + final String methodName = (String)infos[0]; + final int length = methodName.length(); + if (length < getMinLength()) { + return "TestNG test method name <code>#ref</code> is too short (" + length + " < " + getMinLength() + ") #loc"; + } + else if (length > getMaxLength()) { + return "TestNG test method name <code>#ref</code> is too long (" + length + " > " + getMaxLength() + ") #loc"; + } + return "JUnit4 test method name <code>#ref</code> doesn't match regex '{0}' #loc"; + } + + @Override + protected String getDefaultRegex() { + return "[a-z][A-Za-z_\\d]*"; + } + + @Override + protected int getDefaultMinLength() { + return 4; + } + + @Override + protected int getDefaultMaxLength() { + return 64; + } + + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + return new RenameFix(); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new TestNGMethodNamingConventionVisitor(); + } + + private class TestNGMethodNamingConventionVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (!TestNGUtil.hasTest(method)) { + return; + } + final PsiIdentifier nameIdentifier = method.getNameIdentifier(); + if (nameIdentifier == null) { + return; + } + final String name = method.getName(); + if (isValid(name)) { + return; + } + if (!isOnTheFly() && MethodUtils.hasSuper(method)) { + return; + } + if (LibraryUtil.isOverrideOfLibraryMethod(method)) { + return; + } + registerMethodError(method, name); + } + } +} diff --git a/plugins/testng/src/com/theoryinpractice/testng/model/TestNGRemoteListener.java b/plugins/testng/src/com/theoryinpractice/testng/model/TestNGRemoteListener.java index cf8598d8ae3f..b4e89b28a5c6 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/model/TestNGRemoteListener.java +++ b/plugins/testng/src/com/theoryinpractice/testng/model/TestNGRemoteListener.java @@ -48,10 +48,6 @@ public class TestNGRemoteListener implements IRemoteSuiteListener, IRemoteTestLi public void onFinish(SuiteMessage suiteMessage) { unboundOutputRoot.flush(); console.finish(); - final TestNGResults view = console.getResultsView(); - if (view != null) { - view.finish(); - } } public void onStart(TestMessage tm) { diff --git a/plugins/testng/src/com/theoryinpractice/testng/ui/ResultTreeRenderer.java b/plugins/testng/src/com/theoryinpractice/testng/ui/ResultTreeRenderer.java index ba30f43b66f0..9ea4429447fe 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/ui/ResultTreeRenderer.java +++ b/plugins/testng/src/com/theoryinpractice/testng/ui/ResultTreeRenderer.java @@ -16,6 +16,7 @@ package com.theoryinpractice.testng.ui; import com.intellij.execution.testframework.PoolOfTestIcons; +import com.intellij.execution.testframework.TestFrameworkRunningModel; import com.intellij.icons.AllIcons; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; @@ -34,10 +35,11 @@ import javax.swing.tree.DefaultMutableTreeNode; */ public class ResultTreeRenderer extends ColoredTreeCellRenderer { - private final TestNGConsoleProperties consoleProperties; - public ResultTreeRenderer(TestNGConsoleProperties consoleProperties) { - this.consoleProperties = consoleProperties; + private TestFrameworkRunningModel model; + + public ResultTreeRenderer(TestFrameworkRunningModel model) { + this.model = model; } @Override @@ -47,7 +49,7 @@ public class ResultTreeRenderer extends ColoredTreeCellRenderer TestProxy proxy = ((TestNodeDescriptor) node.getUserObject()).getElement(); if (node == tree.getModel().getRoot()) { TreeRootNode root = (TreeRootNode) proxy; - if (node.getChildCount() == 0) { + if (node.getChildCount() == 0 && !((TestNGResults)model).hasFinishedTests()) { if ((root.isStarted() && root.isInProgress()) || (root.isInProgress() && !root.isStarted())) { setIcon(PoolOfTestIcons.NOT_RAN); append("Instantiating tests... ", SimpleTextAttributes.REGULAR_ATTRIBUTES); @@ -64,13 +66,13 @@ public class ResultTreeRenderer extends ColoredTreeCellRenderer append(root.isInProgress() ? "Running tests..." : "Test Results", SimpleTextAttributes.REGULAR_ATTRIBUTES); } - if (consoleProperties.isPaused()) { + if (model.getProperties().isPaused()) { setIcon(AllIcons.RunConfigurations.TestPaused); } } else { if (proxy.getResultMessage() != null) { final TestResultMessage result = proxy.getResultMessage(); - final String name = TestProxy.toDisplayText(result, consoleProperties.getProject()); + final String name = TestProxy.toDisplayText(result, model.getProperties().getProject()); append(name, SimpleTextAttributes.REGULAR_ATTRIBUTES); } else { append(proxy.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES); diff --git a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java index 442e03440ac5..78f980aea83d 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java +++ b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGResults.java @@ -378,7 +378,7 @@ public class TestNGResults extends TestResultsPanel implements TestFrameworkRunn rootNode.setStarted(true); } - public void finish() { + public void finish(final boolean started) { if (start > 0) { end = System.currentTimeMillis(); } @@ -409,6 +409,7 @@ public class TestNGResults extends TestResultsPanel implements TestFrameworkRunn } } tree.repaint(); + TestsUIUtil.notifyByBalloon(project, started, rootNode, getProperties(), "in " + getTime()); } }); } @@ -466,6 +467,10 @@ public class TestNGResults extends TestResultsPanel implements TestFrameworkRunn this.failedToStart = failedToStart; } + public boolean hasFinishedTests() { + return count > 0; + } + private class OpenSourceSelectionListener implements TreeSelectionListener { public void valueChanged(TreeSelectionEvent e) { diff --git a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGTestTreeView.java b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGTestTreeView.java index 48f252d828ee..7e5b7995af0c 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGTestTreeView.java +++ b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGTestTreeView.java @@ -33,7 +33,7 @@ import javax.swing.tree.TreeSelectionModel; public class TestNGTestTreeView extends TestTreeView { protected TreeCellRenderer getRenderer(final TestConsoleProperties properties) { - return new ResultTreeRenderer((TestNGConsoleProperties)properties); + return new ResultTreeRenderer(getTestFrameworkRunningModel()); } public TestProxy getSelectedTest(@NotNull TreePath treepath) { diff --git a/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java b/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java index a3538059b1db..597bb5983876 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java +++ b/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java @@ -8,25 +8,26 @@ import com.intellij.execution.actions.JavaRerunFailedTestsAction; import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.testframework.AbstractTestProxy; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComponentContainer; +import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.containers.ContainerUtil; import com.theoryinpractice.testng.configuration.SearchingForTestsTask; import com.theoryinpractice.testng.configuration.TestNGConfiguration; import com.theoryinpractice.testng.configuration.TestNGRunnableState; +import com.theoryinpractice.testng.util.TestNGUtil; import org.jetbrains.annotations.NotNull; import java.io.File; import java.net.ServerSocket; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; public class RerunFailedTestsAction extends JavaRerunFailedTestsAction { @@ -53,6 +54,19 @@ public class RerunFailedTestsAction extends JavaRerunFailedTestsAction { return new SearchingForTestsTask(serverSocket, config, tempFile, client) { @Override protected void fillTestObjects(final Map<PsiClass, Collection<PsiMethod>> classes) throws CantRunException { + final HashMap<PsiClass, Collection<PsiMethod>> fullClassList = ContainerUtil.newHashMap(); + super.fillTestObjects(fullClassList); + for (final PsiClass aClass : fullClassList.keySet()) { + if (!ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { + @Override + public Boolean compute() { + return TestNGUtil.hasTest(aClass); + } + })) { + classes.put(aClass, fullClassList.get(aClass)); + } + } + final GlobalSearchScope scope = config.getConfigurationModule().getSearchScope(); final Project project = config.getProject(); for (AbstractTestProxy proxy : failedTests) { diff --git a/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java b/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java index c707a5e86e4e..565af249a27f 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java +++ b/plugins/testng/src/com/theoryinpractice/testng/util/TestNGUtil.java @@ -113,25 +113,27 @@ public class TestNGUtil { private static final String SUITE_TAG_NAME = "suite"; public static boolean hasConfig(PsiModifierListOwner element) { - PsiMethod[] methods; if (element instanceof PsiClass) { - methods = ((PsiClass) element).getMethods(); + for (PsiMethod method : ((PsiClass)element).getAllMethods()) { + if (isConfigMethod(method)) return true; + } } else { if (!(element instanceof PsiMethod)) return false; - methods = new PsiMethod[] {(PsiMethod) element}; + return isConfigMethod((PsiMethod)element); } + return false; + } - for (PsiMethod method : methods) { - for (String fqn : CONFIG_ANNOTATIONS_FQN) { - if (AnnotationUtil.isAnnotated(method, fqn, false)) return true; - } + private static boolean isConfigMethod(PsiMethod method) { + for (String fqn : CONFIG_ANNOTATIONS_FQN) { + if (AnnotationUtil.isAnnotated(method, fqn, false)) return true; + } - if (hasDocTagsSupport) { - final PsiDocComment comment = method.getDocComment(); - if (comment != null) { - for (String javadocTag : CONFIG_JAVADOC_TAGS) { - if (comment.findTagByName(javadocTag) != null) return true; - } + if (hasDocTagsSupport) { + final PsiDocComment comment = method.getDocComment(); + if (comment != null) { + for (String javadocTag : CONFIG_JAVADOC_TAGS) { + if (comment.findTagByName(javadocTag) != null) return true; } } } @@ -178,13 +180,7 @@ public class TestNGUtil { if (checkDisabled) { PsiAnnotation annotation = AnnotationUtil.findAnnotation(element, true, TEST_ANNOTATION_FQN); if (annotation != null) { - PsiNameValuePair[] attribs = annotation.getParameterList().getAttributes(); - for (PsiNameValuePair attrib : attribs) { - final String attribName = attrib.getName(); - final PsiAnnotationMemberValue attribValue = attrib.getValue(); - if (Comparing.strEqual(attribName, "enabled") && attribValue != null && attribValue.textMatches("false")) - return false; - } + if (isDisabled(annotation)) return false; } } return true; @@ -207,7 +203,7 @@ public class TestNGUtil { if (AnnotationUtil.isAnnotated(psiClass, TEST_ANNOTATION_FQN, true, true)) { //even if it has a global test, we ignore private methods boolean isPrivate = element.hasModifierProperty(PsiModifier.PRIVATE); - return !isPrivate; + return !isPrivate && !element.hasModifierProperty(PsiModifier.STATIC) && !hasConfig(element); } if (hasTestJavaDoc(psiClass, checkJavadoc)) return true; } @@ -215,6 +211,11 @@ public class TestNGUtil { return false; } + public static boolean isDisabled(PsiAnnotation annotation) { + final PsiAnnotationMemberValue attributeValue = annotation.findDeclaredAttributeValue("enabled"); + return attributeValue != null && attributeValue.textMatches("false"); + } + private static boolean hasTestJavaDoc(@NotNull PsiDocCommentOwner element, final boolean checkJavadoc) { if (checkJavadoc) { return getTextJavaDoc(element) != null; diff --git a/plugins/testng/src/inspectionDescriptions/TestNGMethodNamingConvention.html b/plugins/testng/src/inspectionDescriptions/TestNGMethodNamingConvention.html new file mode 100644 index 000000000000..2303a201c5d9 --- /dev/null +++ b/plugins/testng/src/inspectionDescriptions/TestNGMethodNamingConvention.html @@ -0,0 +1,13 @@ +<html> +<body> +Reports TestNG test methods whose names are either too short, too long, or do not follow the specified regular expression pattern. +When this inspection is enabled, the <i>Instance method naming convention</i> inspection +will ignore TestNG test methods automatically. +<!-- tooltip end --> +<p> + Use the fields below to specify minimum length, maximum length and regular expression expected for TestNG test method names. + Specify <b>0</b> to not check the length of names. Regular expressions are in standard <b>java.util.regex</b> format. +<p> + <small>New in 14</small> +</body> +</html>
\ No newline at end of file diff --git a/plugins/testng/testData/inspection/dependsOn/Dependencies.java b/plugins/testng/testData/inspection/dependsOn/Dependencies.java index 9111c74affd0..fc095a3ecd3d 100644 --- a/plugins/testng/testData/inspection/dependsOn/Dependencies.java +++ b/plugins/testng/testData/inspection/dependsOn/Dependencies.java @@ -14,6 +14,12 @@ import org.testng.annotations.*; @BeforeMethod(dependsOnMethods = <warning descr="Method 'afterSuiteMethod' is not annotated with @org.testng.annotations.BeforeMethod">"afterSuiteMethod"</warning>) public final void beforeMethod() throws Throwable { } -} + + @Test(dependsOnMethods = <warning descr="Method 'foo*' unknown.">"foo*"</warning>) + public void testBar2() {} + + @Test(dependsOnMethods = "testBa*") + public void testBar1() {} + } diff --git a/plugins/ui-designer-core/src/com/intellij/designer/propertyTable/actions/ShowJavadoc.java b/plugins/ui-designer-core/src/com/intellij/designer/propertyTable/actions/ShowJavadoc.java index 459d18ae2bab..6f42108cab9a 100644 --- a/plugins/ui-designer-core/src/com/intellij/designer/propertyTable/actions/ShowJavadoc.java +++ b/plugins/ui-designer-core/src/com/intellij/designer/propertyTable/actions/ShowJavadoc.java @@ -33,7 +33,6 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.ui.awt.RelativePoint; -import com.intellij.ui.popup.NotLookupOrSearchCondition; import java.awt.*; @@ -101,7 +100,6 @@ public class ShowJavadoc extends AnAction implements IPropertyTableAction { public void run() { JBPopup hint = JBPopupFactory.getInstance().createComponentPopupBuilder(component, component) - .setRequestFocusCondition(project, NotLookupOrSearchCondition.INSTANCE) .setProject(project) .setDimensionServiceKey(project, DocumentationManager.JAVADOC_LOCATION_AND_SIZE, false) .setResizable(true) diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/AbstractCreateFormAction.java b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/AbstractCreateFormAction.java index a5cd762fcf15..0377b72ea043 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/AbstractCreateFormAction.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/AbstractCreateFormAction.java @@ -31,6 +31,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.JavaDirectoryService; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiNameHelper; import com.intellij.uiDesigner.UIDesignerBundle; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; @@ -104,7 +105,7 @@ public abstract class AbstractCreateFormAction extends CreateElementActionBase i @Override public boolean checkInput(String inputString) { - return inputString.length() > 0 && JavaPsiFacade.getInstance(myProject).getNameHelper().isQualifiedName(inputString); + return inputString.length() > 0 && PsiNameHelper.getInstance(myProject).isQualifiedName(inputString); } } }
\ No newline at end of file diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/GenerateMainAction.java b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/GenerateMainAction.java index d698a076b891..a9996ba276d0 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/GenerateMainAction.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/GenerateMainAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -21,7 +21,6 @@ import com.intellij.codeInsight.generation.PsiGenerationInfo; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; @@ -146,7 +145,7 @@ public class GenerateMainAction extends AnAction { PsiClass psiClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); if (psiClass == null) return false; if (PsiMethodUtil.findMainMethod(psiClass) != null) return false; - if (FormClassIndex.findFormsBoundToClass(psiClass).isEmpty()) return false; + if (FormClassIndex.findFormsBoundToClass(project, psiClass).isEmpty()) return false; return true; } } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/BoundIconRenderer.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/BoundIconRenderer.java index 48816354893d..60f12b2489b6 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/BoundIconRenderer.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/BoundIconRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -124,7 +124,7 @@ public class BoundIconRenderer extends GutterIconRenderer { aClass = (PsiClass) myElement; } if (aClass != null && aClass.getQualifiedName() != null) { - formFiles = FormClassIndex.findFormsBoundToClass(aClass); + formFiles = FormClassIndex.findFormsBoundToClass(aClass.getProject(), aClass); } return formFiles; } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassAnnotator.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassAnnotator.java index 0733ad85c781..05c1bcb1b912 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassAnnotator.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassAnnotator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 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. @@ -47,7 +47,7 @@ public class FormClassAnnotator implements Annotator { } else if (psiElement instanceof PsiClass) { PsiClass aClass = (PsiClass) psiElement; - final List<PsiFile> formsBoundToClass = FormClassIndex.findFormsBoundToClass(aClass); + final List<PsiFile> formsBoundToClass = FormClassIndex.findFormsBoundToClass(aClass.getProject(), aClass); if (formsBoundToClass.size() > 0) { Annotation boundClassAnnotation = holder.createInfoAnnotation(aClass.getNameIdentifier(), null); boundClassAnnotation.setGutterIconRenderer(new BoundIconRenderer(aClass)); diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java index 0bf86d73618b..000b63716ef4 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java @@ -127,15 +127,15 @@ public class FormClassIndex extends ScalarIndexExtension<String> { }); } - public static List<PsiFile> findFormsBoundToClass(@NotNull PsiClass psiClass) { + public static List<PsiFile> findFormsBoundToClass(Project project, @NotNull PsiClass psiClass) { String qName = FormReferencesSearcher.getQualifiedName(psiClass); if (qName == null) return Collections.emptyList(); - return findFormsBoundToClass(psiClass.getProject(), qName); + return findFormsBoundToClass(project, qName); } - public static List<PsiFile> findFormsBoundToClass(PsiClass psiClass, GlobalSearchScope scope) { + public static List<PsiFile> findFormsBoundToClass(Project project, PsiClass psiClass, GlobalSearchScope scope) { String qName = FormReferencesSearcher.getQualifiedName(psiClass); if (qName == null) return Collections.emptyList(); - return findFormsBoundToClass(psiClass.getProject(), qName, scope); + return findFormsBoundToClass(project, qName, scope); } } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormReferenceProvider.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormReferenceProvider.java index c0ef7a143a41..173ae3a3a7c1 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormReferenceProvider.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormReferenceProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -83,7 +83,7 @@ public class FormReferenceProvider extends PsiReferenceProvider { public static PsiReference getFormReference(PsiField field) { final PsiClass containingClass = field.getContainingClass(); if (containingClass != null && containingClass.getQualifiedName() != null) { - final List<PsiFile> forms = FormClassIndex.findFormsBoundToClass(containingClass); + final List<PsiFile> forms = FormClassIndex.findFormsBoundToClass(containingClass.getProject(), containingClass); for (PsiFile formFile : forms) { final PsiReference[] refs = formFile.getReferences(); for (final PsiReference ref : refs) { diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormReferencesSearcher.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormReferencesSearcher.java index 179f47d57a47..d40be21e1786 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormReferencesSearcher.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormReferencesSearcher.java @@ -1,3 +1,18 @@ +/* + * 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.uiDesigner.binding; import com.intellij.lang.properties.IProperty; @@ -15,7 +30,6 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.NullableComputable; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.psi.impl.cache.CacheManager; import com.intellij.psi.impl.search.PsiSearchHelperImpl; import com.intellij.psi.search.*; @@ -27,16 +41,19 @@ import com.intellij.util.QueryExecutor; import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; import java.util.List; /** * @author max */ public class FormReferencesSearcher implements QueryExecutor<PsiReference, ReferencesSearch.SearchParameters> { + @Override public boolean execute(@NotNull final ReferencesSearch.SearchParameters p, @NotNull final Processor<PsiReference> consumer) { if (!scopeCanContainForms(p.getScope())) return true; final PsiElement refElement = p.getElementToSearch(); final PsiFile psiFile = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() { + @Override public PsiFile compute() { if (!refElement.isValid()) return null; return refElement.getContainingFile(); @@ -45,31 +62,38 @@ public class FormReferencesSearcher implements QueryExecutor<PsiReference, Refer if (psiFile == null) return true; final VirtualFile virtualFile = psiFile.getVirtualFile(); if (virtualFile == null) return true; - Module module = ProjectRootManager.getInstance(refElement.getProject()).getFileIndex().getModuleForFile(virtualFile); + Project project = ApplicationManager.getApplication().runReadAction(new Computable<Project>() { + @Override + public Project compute() { + return psiFile.getProject(); + } + }); + Module module = ProjectRootManager.getInstance(project).getFileIndex().getModuleForFile(virtualFile); if (module == null) return true; final GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesScope(module); final LocalSearchScope filterScope = p.getScope() instanceof LocalSearchScope ? (LocalSearchScope) p.getScope() : null; + PsiManager psiManager = PsiManager.getInstance(project); if (refElement instanceof PsiPackage) { //no need to do anything //if (!UIFormUtil.processReferencesInUIForms(consumer, (PsiPackage)refElement, scope)) return false; } else if (refElement instanceof PsiClass) { - if (!processReferencesInUIForms(consumer, (PsiClass)refElement, scope, filterScope)) return false; + if (!processReferencesInUIForms(consumer, psiManager,(PsiClass)refElement, scope, filterScope)) return false; } else if (refElement instanceof PsiEnumConstant) { - if (!processReferencesInUIForms(consumer, (PsiEnumConstant)refElement, scope, filterScope)) return false; + if (!processReferencesInUIForms(consumer, psiManager, (PsiEnumConstant)refElement, scope, filterScope)) return false; } else if (refElement instanceof PsiField) { - if (!processReferencesInUIForms(consumer, (PsiField)refElement, scope, filterScope)) return false; + if (!processReferencesInUIForms(consumer, psiManager, (PsiField)refElement, scope, filterScope)) return false; } else if (refElement instanceof IProperty) { - if (!processReferencesInUIForms(consumer, (Property)refElement, scope, filterScope)) return false; + if (!processReferencesInUIForms(consumer, psiManager, (Property)refElement, scope, filterScope)) return false; } else if (refElement instanceof PropertiesFile) { - if (!processReferencesInUIForms(consumer, (PropertiesFile)refElement, scope, filterScope)) return false; + if (!processReferencesInUIForms(consumer, psiManager, (PropertiesFile)refElement, scope, filterScope)) return false; } return true; @@ -79,31 +103,37 @@ public class FormReferencesSearcher implements QueryExecutor<PsiReference, Refer if (!(scope instanceof LocalSearchScope)) return true; LocalSearchScope localSearchScope = (LocalSearchScope) scope; final PsiElement[] elements = localSearchScope.getScope(); - for (PsiElement element : elements) { + for (final PsiElement element : elements) { if (element instanceof PsiDirectory) return true; - PsiFile file; - if (element instanceof PsiFile) { - file = (PsiFile) element; - } - else { - if (!element.isValid()) continue; - file = element.getContainingFile(); - } - if (file.getFileType() == StdFileTypes.GUI_DESIGNER_FORM) return true; + boolean isForm = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { + @Override + public Boolean compute() { + PsiFile file; + if (element instanceof PsiFile) { + file = (PsiFile)element; + } + else { + if (!element.isValid()) return false; + file = element.getContainingFile(); + } + return file.getFileType() == StdFileTypes.GUI_DESIGNER_FORM; + } + }); + if (isForm) return true; } return false; } private static boolean processReferencesInUIForms(Processor<PsiReference> processor, - final PsiClass aClass, - GlobalSearchScope scope, final LocalSearchScope filterScope) { - PsiManagerImpl manager = (PsiManagerImpl)aClass.getManager(); + PsiManager psiManager, final PsiClass aClass, + GlobalSearchScope scope, final LocalSearchScope filterScope) { String className = getQualifiedName(aClass); - return className == null || processReferencesInUIFormsInner(className, aClass, processor, scope, manager, filterScope); + return className == null || processReferencesInUIFormsInner(className, aClass, processor, scope, psiManager, filterScope); } public static String getQualifiedName(final PsiClass aClass) { return ApplicationManager.getApplication().runReadAction(new Computable<String>() { + @Override public String compute() { if (!aClass.isValid()) return null; return aClass.getQualifiedName(); @@ -112,83 +142,56 @@ public class FormReferencesSearcher implements QueryExecutor<PsiReference, Refer } private static boolean processReferencesInUIForms(Processor<PsiReference> processor, - final PsiEnumConstant enumConstant, + PsiManager psiManager, final PsiEnumConstant enumConstant, GlobalSearchScope scope, final LocalSearchScope filterScope) { - PsiManagerImpl manager = (PsiManagerImpl)enumConstant.getManager(); String className = ApplicationManager.getApplication().runReadAction(new Computable<String>() { @Override public String compute() { return enumConstant.getName(); } }); - return className == null || processReferencesInUIFormsInner(className, enumConstant, processor, scope, manager, filterScope); - + return className == null || processReferencesInUIFormsInner(className, enumConstant, processor, scope, psiManager, filterScope); } private static boolean processReferencesInUIFormsInner(String name, PsiElement element, Processor<PsiReference> processor, GlobalSearchScope scope1, - PsiManagerImpl manager, + PsiManager manager, final LocalSearchScope filterScope) { GlobalSearchScope scope = GlobalSearchScope.projectScope(manager.getProject()).intersectWith(scope1); - manager.startBatchFilesProcessingMode(); - - try { - List<PsiFile> files = FormClassIndex.findFormsBoundToClass(manager.getProject(), name, scope); - - for (PsiFile file : files) { - ProgressManager.checkCanceled(); + List<PsiFile> files = FormClassIndex.findFormsBoundToClass(manager.getProject(), name, scope); - if (file.getFileType() != StdFileTypes.GUI_DESIGNER_FORM) continue; - if (!processReferences(processor, file, name, element, filterScope)) return false; - } - } - finally { - manager.finishBatchFilesProcessingMode(); - } - - return true; + return processReferencesInFiles(files, manager, name, element, filterScope, processor); } private static boolean processReferencesInUIForms(Processor<PsiReference> processor, - PsiField field, - GlobalSearchScope scope1, - LocalSearchScope filterScope) { - GlobalSearchScope scope = GlobalSearchScope.projectScope(field.getProject()).intersectWith(scope1); - PsiManagerImpl manager = (PsiManagerImpl)field.getManager(); + PsiManager psiManager, + PsiField field, + GlobalSearchScope scope1, + LocalSearchScope filterScope) { + GlobalSearchScope scope = GlobalSearchScope.projectScope(psiManager.getProject()).intersectWith(scope1); + final AccessToken token = ReadAction.start(); PsiClass containingClass = field.getContainingClass(); if (containingClass == null) return true; String fieldName; - final AccessToken token = ReadAction.start(); try { fieldName = field.getName(); } finally { token.finish(); } - manager.startBatchFilesProcessingMode(); - - try { - final List<PsiFile> files = FormClassIndex.findFormsBoundToClass(containingClass, scope); - - for (PsiFile file : files) { - ProgressManager.checkCanceled(); - - if (file.getFileType() != StdFileTypes.GUI_DESIGNER_FORM) continue; - if (!processReferences(processor, file, fieldName, field, filterScope)) return false; - } - } - finally { - manager.finishBatchFilesProcessingMode(); - } - - return true; + final List<PsiFile> files = FormClassIndex.findFormsBoundToClass(psiManager.getProject(), containingClass, scope); + return processReferencesInFiles(files, psiManager, fieldName, field, filterScope, processor); } - private static boolean processReferences(final Processor<PsiReference> processor, final PsiFile file, String name, final PsiElement element, + private static boolean processReferences(final Processor<PsiReference> processor, + final PsiFile file, + String name, + final PsiElement element, final LocalSearchScope filterScope) { CharSequence chars = ApplicationManager.getApplication().runReadAction(new NullableComputable<CharSequence>() { + @Override public CharSequence compute() { if (filterScope != null) { boolean isInScope = false; @@ -211,6 +214,7 @@ public class FormReferencesSearcher implements QueryExecutor<PsiReference, Refer if (index < 0) break; final int finalIndex = index; final Boolean searchDone = ApplicationManager.getApplication().runReadAction(new NullableComputable<Boolean>() { + @Override public Boolean compute() { final PsiReference ref = file.findReferenceAt(finalIndex + offset + 1); if (ref != null && ref.isReferenceTo(element)) { @@ -227,13 +231,13 @@ public class FormReferencesSearcher implements QueryExecutor<PsiReference, Refer } private static boolean processReferencesInUIForms(final Processor<PsiReference> processor, - final Property property, - final GlobalSearchScope globalSearchScope, - final LocalSearchScope filterScope) { + PsiManager psiManager, + final Property property, + final GlobalSearchScope globalSearchScope, + final LocalSearchScope filterScope) { + final Project project = psiManager.getProject(); - final Project project = property.getProject(); final GlobalSearchScope scope = GlobalSearchScope.projectScope(project).intersectWith(globalSearchScope); - final PsiManagerImpl manager = (PsiManagerImpl)property.getManager(); String name = ApplicationManager.getApplication().runReadAction(new Computable<String>() { @Override public String compute() { @@ -242,7 +246,7 @@ public class FormReferencesSearcher implements QueryExecutor<PsiReference, Refer }); if (name == null) return true; - manager.startBatchFilesProcessingMode(); + psiManager.startBatchFilesProcessingMode(); try { CommonProcessors.CollectProcessor<VirtualFile> collector = new CommonProcessors.CollectProcessor<VirtualFile>() { @@ -268,34 +272,54 @@ public class FormReferencesSearcher implements QueryExecutor<PsiReference, Refer } } finally { - manager.finishBatchFilesProcessingMode(); + psiManager.finishBatchFilesProcessingMode(); } return true; } - private static boolean processReferencesInUIForms(final Processor<PsiReference> processor, final PropertiesFile propFile, final GlobalSearchScope globalSearchScope, - final LocalSearchScope filterScope) { - final Project project = propFile.getProject(); + private static boolean processReferencesInUIForms(final Processor<PsiReference> processor, + PsiManager psiManager, + final PropertiesFile propFile, + final GlobalSearchScope globalSearchScope, + final LocalSearchScope filterScope) { + final Project project = psiManager.getProject(); GlobalSearchScope scope = GlobalSearchScope.projectScope(project).intersectWith(globalSearchScope); - PsiManagerImpl manager = (PsiManagerImpl)propFile.getContainingFile().getManager(); - final String baseName = propFile.getResourceBundle().getBaseName(); - manager.startBatchFilesProcessingMode(); + final String baseName = ApplicationManager.getApplication().runReadAction(new Computable<String>() { + @Override + public String compute() { + return propFile.getResourceBundle().getBaseName(); + } + }); + PsiFile containingFile = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() { + @Override + public PsiFile compute() { + return propFile.getContainingFile(); + } + }); - try { - PsiFile[] files = CacheManager.SERVICE.getInstance(project).getFilesWithWord(baseName, UsageSearchContext.IN_PLAIN_TEXT, scope, true); + List<PsiFile> files = Arrays.asList(CacheManager.SERVICE.getInstance(project).getFilesWithWord(baseName, UsageSearchContext.IN_PLAIN_TEXT, scope, true)); + return processReferencesInFiles(files, psiManager, baseName, containingFile, filterScope, processor); + } + private static boolean processReferencesInFiles(List<PsiFile> files, + PsiManager psiManager, String baseName, + PsiElement element, + LocalSearchScope filterScope, + Processor<PsiReference> processor) { + psiManager.startBatchFilesProcessingMode(); + + try { for (PsiFile file : files) { ProgressManager.checkCanceled(); if (file.getFileType() != StdFileTypes.GUI_DESIGNER_FORM) continue; - if (!processReferences(processor, file, baseName, propFile.getContainingFile(), filterScope)) return false; + if (!processReferences(processor, file, baseName, element, filterScope)) return false; } } finally { - manager.finishBatchFilesProcessingMode(); + psiManager.finishBatchFilesProcessingMode(); } - return true; } } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormRelatedFilesProvider.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormRelatedFilesProvider.java index dbe28385666d..8de344a03f16 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormRelatedFilesProvider.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormRelatedFilesProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 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. @@ -42,7 +42,7 @@ public class FormRelatedFilesProvider extends GotoRelatedProvider { PsiClass psiClass = PsiTreeUtil.getParentOfType(context, PsiClass.class, false); if (psiClass != null) { while (psiClass != null) { - List<PsiFile> forms = FormClassIndex.findFormsBoundToClass(psiClass); + List<PsiFile> forms = FormClassIndex.findFormsBoundToClass(psiClass.getProject(), psiClass); if (!forms.isEmpty()) { return GotoRelatedItem.createItems(forms, "UI Forms"); } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormsRenamer.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormsRenamer.java index cafbb8d2bf73..796aced2a67d 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormsRenamer.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormsRenamer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -39,7 +39,7 @@ public class FormsRenamer extends AutomaticRenamer { public FormsRenamer(PsiClass aClass, String newClassName) { if (aClass.getQualifiedName() != null) { - List<PsiFile> forms = FormClassIndex.findFormsBoundToClass(aClass); + List<PsiFile> forms = FormClassIndex.findFormsBoundToClass(aClass.getProject(), aClass); myElements.addAll(forms); suggestAllNames(aClass.getName(), newClassName); } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormsRenamerFactory.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormsRenamerFactory.java index 7f719850834e..5ffca466a954 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormsRenamerFactory.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormsRenamerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -29,7 +29,7 @@ import java.util.List; public class FormsRenamerFactory implements AutomaticRenamerFactory { public boolean isApplicable(final PsiElement element) { if (!(element instanceof PsiClass)) return false; - List<PsiFile> forms = FormClassIndex.findFormsBoundToClass((PsiClass) element); + List<PsiFile> forms = FormClassIndex.findFormsBoundToClass(element.getProject(), (PsiClass)element); return forms.size() > 0; } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/ResourceBundleFileReference.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/ResourceBundleFileReference.java index f2a9bbb8316d..3064746e9cac 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/ResourceBundleFileReference.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/ResourceBundleFileReference.java @@ -16,8 +16,8 @@ package com.intellij.uiDesigner.binding; import com.intellij.lang.properties.PropertiesFileType; -import com.intellij.lang.properties.PropertiesUtil; import com.intellij.lang.properties.PropertiesUtilBase; +import com.intellij.lang.properties.ResourceBundleManager; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; @@ -61,7 +61,7 @@ public final class ResourceBundleFileReference extends ReferenceInForm { @Override public boolean isReferenceTo(final PsiElement element) { if (!(element instanceof PropertiesFile)) return false; - String baseName = PropertiesUtil.getFullName((PropertiesFile) element); + String baseName = ResourceBundleManager.getInstance(element.getProject()).getFullName((PropertiesFile)element); if (baseName == null) return false; baseName = baseName.replace('.', '/'); final String rangeText = getRangeText(); diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/ResourceBundleKeyReference.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/ResourceBundleKeyReference.java index e6f2bb5930c9..e440400dcbee 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/ResourceBundleKeyReference.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/ResourceBundleKeyReference.java @@ -16,8 +16,8 @@ package com.intellij.uiDesigner.binding; import com.intellij.lang.properties.IProperty; -import com.intellij.lang.properties.PropertiesUtil; import com.intellij.lang.properties.PropertiesUtilBase; +import com.intellij.lang.properties.ResourceBundleManager; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; @@ -74,7 +74,7 @@ public final class ResourceBundleKeyReference extends ReferenceInForm { return false; } IProperty property = (IProperty) element; - String baseName = PropertiesUtil.getFullName(property.getPropertiesFile()); + String baseName = ResourceBundleManager.getInstance(element.getProject()).getFullName(property.getPropertiesFile()); return baseName != null && myBundleName.equals(baseName.replace('.', '/')) && getRangeText().equals(property.getUnescapedKey()); } } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/palette/ComponentItemDialog.java b/plugins/ui-designer/src/com/intellij/uiDesigner/palette/ComponentItemDialog.java index 95be42a02d8b..a3d66a914304 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/palette/ComponentItemDialog.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/palette/ComponentItemDialog.java @@ -325,13 +325,13 @@ public final class ComponentItemDialog extends DialogWrapper { if (myDocument == null) { // why? return false; } - final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(myProject); - if (!javaPsiFacade.getNameHelper().isQualifiedName(myDocument.getText())) { + if (!PsiNameHelper.getInstance(myProject).isQualifiedName(myDocument.getText())) { if (myDocument.getTextLength() > 0) { myErrorLabel.setText(UIDesignerBundle.message("add.component.error.qualified.name.required")); } return false; } + final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(myProject); PsiClass psiClass = javaPsiFacade.findClass(myDocument.getText(), ProjectScope.getAllScope(myProject)); PsiClass componentClass = javaPsiFacade.findClass(JComponent.class.getName(), ProjectScope.getAllScope(myProject)); if (psiClass != null && componentClass != null && !InheritanceUtil.isInheritorOrSelf(psiClass, componentClass, true)) { diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/projectView/Form.java b/plugins/ui-designer/src/com/intellij/uiDesigner/projectView/Form.java index 473593be180e..1b3b00365d8f 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/projectView/Form.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/projectView/Form.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -34,7 +34,7 @@ public class Form implements Navigatable { public Form(PsiClass classToBind) { myClassToBind = classToBind; - myFormFiles = FormClassIndex.findFormsBoundToClass(classToBind); + myFormFiles = FormClassIndex.findFormsBoundToClass(classToBind.getProject(), classToBind); } public Form(PsiClass classToBind, Collection<PsiFile> formFiles) { diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/BindingProperty.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/BindingProperty.java index d4ef25332a60..58306f72167a 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/BindingProperty.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/BindingProperty.java @@ -97,7 +97,7 @@ public final class BindingProperty extends Property<RadComponent, String> { return; } - if (value.length() > 0 && !JavaPsiFacade.getInstance(component.getProject()).getNameHelper().isIdentifier(value)) { + if (value.length() > 0 && !PsiNameHelper.getInstance(component.getProject()).isIdentifier(value)) { throw new Exception("Value '" + value + "' is not a valid identifier"); } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/IdentifierValidator.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/IdentifierValidator.java index 42372bd96104..2a698d3fc6e3 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/IdentifierValidator.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/IdentifierValidator.java @@ -25,6 +25,7 @@ package com.intellij.uiDesigner.propertyInspector.properties; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.InputValidator; import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiNameHelper; public class IdentifierValidator implements InputValidator { private final Project myProject; @@ -34,7 +35,7 @@ public class IdentifierValidator implements InputValidator { } public boolean checkInput(String inputString) { - return JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(inputString); + return PsiNameHelper.getInstance(myProject).isIdentifier(inputString); } public boolean canClose(String inputString) { diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.java b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.java index f273cd32106c..d963bb137aec 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BeanStep.java @@ -154,7 +154,7 @@ final class BeanStep extends StepAdapter{ throw new CommitStepException(UIDesignerBundle.message("error.please.specify.class.name.of.the.bean.to.be.created")); } final PsiManager psiManager = PsiManager.getInstance(myData.myProject); - if(!JavaPsiFacade.getInstance(psiManager.getProject()).getNameHelper().isIdentifier(shortClassName)){ + if(!PsiNameHelper.getInstance(psiManager.getProject()).isIdentifier(shortClassName)){ throw new CommitStepException(UIDesignerBundle.message("error.X.is.not.a.valid.class.name", shortClassName)); } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BindToNewBeanStep.java b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BindToNewBeanStep.java index 0d88412ece9b..00a89febe8b0 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BindToNewBeanStep.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/wizard/BindToNewBeanStep.java @@ -93,7 +93,7 @@ final class BindToNewBeanStep extends StepAdapter{ } // Check that all included fields are bound to valid bean properties - final PsiNameHelper nameHelper = JavaPsiFacade.getInstance(myData.myProject).getNameHelper(); + final PsiNameHelper nameHelper = PsiNameHelper.getInstance(myData.myProject); for(int i = 0; i <myData.myBindings.length; i++){ final FormProperty2BeanProperty binding = myData.myBindings[i]; if(binding.myBeanProperty == null){ diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerRunner.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerRunner.java index f573f9442e64..5fb6888ec1e2 100644 --- a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerRunner.java +++ b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerRunner.java @@ -8,7 +8,6 @@ import com.intellij.execution.runners.DefaultProgramRunner; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.project.Project; import com.intellij.xdebugger.XDebugProcess; import com.intellij.xdebugger.XDebugProcessStarter; import com.intellij.xdebugger.XDebugSession; @@ -19,11 +18,6 @@ import org.intellij.plugins.xsltDebugger.impl.XsltDebugProcess; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -/* -* Created by IntelliJ IDEA. -* User: sweinreuter -* Date: 16.11.10 -*/ public class XsltDebuggerRunner extends DefaultProgramRunner { static final ThreadLocal<Boolean> ACTIVE = new ThreadLocal<Boolean>(); @@ -43,26 +37,20 @@ public class XsltDebuggerRunner extends DefaultProgramRunner { } @Override - protected RunContentDescriptor doExecute(@NotNull Project project, - @NotNull RunProfileState state, - RunContentDescriptor contentToReuse, - @NotNull ExecutionEnvironment env) throws ExecutionException { + protected RunContentDescriptor doExecute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment env) throws ExecutionException { FileDocumentManager.getInstance().saveAllDocuments(); - return createContentDescriptor(project, state, contentToReuse, env); + return createContentDescriptor(state, env); } - protected RunContentDescriptor createContentDescriptor(Project project, - final RunProfileState runProfileState, - RunContentDescriptor contentToReuse, - final ExecutionEnvironment executionEnvironment) throws ExecutionException { + protected RunContentDescriptor createContentDescriptor(final RunProfileState runProfileState, final ExecutionEnvironment environment) throws ExecutionException { final XDebugSession debugSession = - XDebuggerManager.getInstance(project).startSession(this, executionEnvironment, contentToReuse, new XDebugProcessStarter() { + XDebuggerManager.getInstance(environment.getProject()).startSession(environment, new XDebugProcessStarter() { @NotNull public XDebugProcess start(@NotNull final XDebugSession session) throws ExecutionException { ACTIVE.set(Boolean.TRUE); try { final XsltCommandLineState c = (XsltCommandLineState)runProfileState; - final ExecutionResult result = runProfileState.execute(executionEnvironment.getExecutor(), XsltDebuggerRunner.this); + final ExecutionResult result = runProfileState.execute(environment.getExecutor(), XsltDebuggerRunner.this); return new XsltDebugProcess(session, result, c.getExtensionData().getUserData(XsltDebuggerExtension.VERSION)); } finally { ACTIVE.remove(); diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltExecutionStack.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltExecutionStack.java index 3f57574e175c..42d706ae927c 100644 --- a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltExecutionStack.java +++ b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltExecutionStack.java @@ -31,6 +31,7 @@ public class XsltExecutionStack extends XExecutionStack { if (myDebuggerSession.getCurrentState() == Debugger.State.SUSPENDED) { Debugger.Frame frame = myTopFrame.getFrame(); final List<XStackFrame> frames = new ArrayList<XStackFrame>(); + frames.add(myTopFrame); while (frame != null) { frame = frame.getPrevious(); if (frame != null) { @@ -38,7 +39,7 @@ public class XsltExecutionStack extends XExecutionStack { } } if (firstFrameIndex <= frames.size()) { - container.addStackFrames(frames.subList(firstFrameIndex - 1, frames.size()), true); + container.addStackFrames(frames.subList(firstFrameIndex, frames.size()), true); } else { container.addStackFrames(Collections.<XStackFrame>emptyList(), true); } |