mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -1769,6 +1769,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
|
||||
ApplicationManager.getApplication().assertIsDispatchThread(); //TODO: remove this requirement
|
||||
((XDebugSessionImpl)getXdebugProcess().getSession()).reset();
|
||||
myState.set(STATE_INITIAL);
|
||||
myRequestManager.processDetached(this, false);
|
||||
myConnection = environment.getRemoteConnection();
|
||||
getManagerThread().restartIfNeeded();
|
||||
createVirtualMachine(environment.getSessionName(), environment.isPollConnection());
|
||||
|
||||
@@ -22,10 +22,11 @@ import com.intellij.execution.junit2.info.MethodLocation;
|
||||
import com.intellij.execution.testframework.sm.runner.SMTestLocator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.ClassUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -50,32 +51,27 @@ public class JavaTestLocator implements SMTestLocator {
|
||||
path = path.substring(0, idx);
|
||||
}
|
||||
|
||||
JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
|
||||
if (SUITE_PROTOCOL.equals(protocol)) {
|
||||
path = StringUtil.trimEnd(path, ".");
|
||||
PsiClass[] classes = javaPsiFacade.findClasses(path, scope);
|
||||
if (classes.length > 0) {
|
||||
PsiClass aClass = ClassUtil.findPsiClass(PsiManager.getInstance(project), path, null, true, scope);
|
||||
if (aClass != null) {
|
||||
results = ContainerUtil.newSmartList();
|
||||
for (PsiClass aClass : classes) {
|
||||
results.add(paramName != null ? PsiMemberParameterizedLocation.getParameterizedLocation(aClass, paramName)
|
||||
: new PsiLocation<PsiClass>(project, aClass));
|
||||
}
|
||||
results.add(paramName != null ? PsiMemberParameterizedLocation.getParameterizedLocation(aClass, paramName)
|
||||
: new PsiLocation<PsiClass>(project, aClass));
|
||||
}
|
||||
}
|
||||
else if (TEST_PROTOCOL.equals(protocol)) {
|
||||
String className = StringUtil.getPackageName(path);
|
||||
if (!StringUtil.isEmpty(className)) {
|
||||
String methodName = StringUtil.getShortName(path);
|
||||
PsiClass[] classes = javaPsiFacade.findClasses(className, scope);
|
||||
if (classes.length > 0) {
|
||||
PsiClass aClass = ClassUtil.findPsiClass(PsiManager.getInstance(project), className, null, true, scope);
|
||||
if (aClass != null) {
|
||||
results = ContainerUtil.newSmartList();
|
||||
for (PsiClass aClass : classes) {
|
||||
PsiMethod[] methods = aClass.findMethodsByName(methodName, true);
|
||||
if (methods.length > 0) {
|
||||
for (PsiMethod method : methods) {
|
||||
results.add(paramName != null ? new PsiMemberParameterizedLocation(project, method, aClass, paramName)
|
||||
: MethodLocation.elementInClass(method, aClass));
|
||||
}
|
||||
PsiMethod[] methods = aClass.findMethodsByName(methodName, true);
|
||||
if (methods.length > 0) {
|
||||
for (PsiMethod method : methods) {
|
||||
results.add(paramName != null ? new PsiMemberParameterizedLocation(project, method, aClass, paramName)
|
||||
: MethodLocation.elementInClass(method, aClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.ExpectedTypeInfo;
|
||||
import com.intellij.codeInsight.ExpectedTypeInfoImpl;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupItem;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.statistics.JavaStatisticsManager;
|
||||
import com.intellij.psi.statistics.StatisticsInfo;
|
||||
@@ -27,10 +28,13 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class JavaCompletionStatistician extends CompletionStatistician{
|
||||
private static final ElementPattern<PsiElement> SUPER_CALL = psiElement().afterLeaf(psiElement().withText(".").afterLeaf(PsiKeyword.SUPER));
|
||||
|
||||
@Override
|
||||
public StatisticsInfo serialize(final LookupElement element, final CompletionLocation location) {
|
||||
@@ -40,6 +44,10 @@ public class JavaCompletionStatistician extends CompletionStatistician{
|
||||
return StatisticsInfo.EMPTY;
|
||||
}
|
||||
|
||||
if (SUPER_CALL.accepts(location.getCompletionParameters().getPosition())) {
|
||||
return StatisticsInfo.EMPTY;
|
||||
}
|
||||
|
||||
LookupItem item = element.as(LookupItem.CLASS_CONDITION_KEY);
|
||||
if (item == null) return null;
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.psi.util;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiSubstitutor;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public abstract class JavaClassSupers {
|
||||
|
||||
public static JavaClassSupers getInstance() {
|
||||
return ServiceManager.getService(JavaClassSupers.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates substitutor that binds type parameters in <code>superClass</code> with
|
||||
* values that they have in <code>derivedClass</code>, given that type parameters in
|
||||
* <code>derivedClass</code> are bound by <code>derivedSubstitutor</code>.
|
||||
*
|
||||
* @return substitutor or <code>null</code>, if <code>derivedClass</code> doesn't inherit <code>superClass</code>
|
||||
* @see PsiClass#isInheritor(PsiClass, boolean)
|
||||
* @see InheritanceUtil#isInheritorOrSelf(PsiClass, PsiClass, boolean)
|
||||
*/
|
||||
@Nullable
|
||||
public abstract PsiSubstitutor getSuperClassSubstitutor(@NotNull PsiClass superClass,
|
||||
@NotNull PsiClass derivedClass,
|
||||
@NotNull GlobalSearchScope resolveScope,
|
||||
@NotNull PsiSubstitutor derivedSubstitutor);
|
||||
|
||||
|
||||
}
|
||||
@@ -830,7 +830,7 @@ public class TypeConversionUtil {
|
||||
&& rText.endsWith(lText)
|
||||
&& rText.charAt(rText.length() - lText.length() - 1) == '.';
|
||||
}
|
||||
return isClassAssignable(leftResult, rightResult, allowUncheckedConversion);
|
||||
return isClassAssignable(leftResult, rightResult, allowUncheckedConversion, left.getResolveScope());
|
||||
}
|
||||
|
||||
private static boolean isAssignableFromWildcard(@NotNull PsiType left, @NotNull PsiWildcardType rightWildcardType) {
|
||||
@@ -923,18 +923,19 @@ public class TypeConversionUtil {
|
||||
|
||||
private static boolean isClassAssignable(@NotNull PsiClassType.ClassResolveResult leftResult,
|
||||
@NotNull PsiClassType.ClassResolveResult rightResult,
|
||||
boolean allowUncheckedConversion) {
|
||||
boolean allowUncheckedConversion, GlobalSearchScope resolveScope) {
|
||||
final PsiClass leftClass = leftResult.getElement();
|
||||
final PsiClass rightClass = rightResult.getElement();
|
||||
return leftClass != null
|
||||
&& rightClass != null
|
||||
&& InheritanceUtil.isInheritorOrSelf(rightClass, leftClass, true)
|
||||
&& typeParametersAgree(leftResult, rightResult, allowUncheckedConversion);
|
||||
if (leftClass == null || rightClass == null) return false;
|
||||
|
||||
PsiSubstitutor superSubstitutor = JavaClassSupers.getInstance().getSuperClassSubstitutor(leftClass, rightClass, resolveScope,
|
||||
rightResult.getSubstitutor());
|
||||
return superSubstitutor != null && typeParametersAgree(leftResult, rightResult, allowUncheckedConversion, superSubstitutor);
|
||||
}
|
||||
|
||||
private static boolean typeParametersAgree(@NotNull PsiClassType.ClassResolveResult leftResult,
|
||||
@NotNull PsiClassType.ClassResolveResult rightResult,
|
||||
boolean allowUncheckedConversion) {
|
||||
boolean allowUncheckedConversion, PsiSubstitutor superSubstitutor) {
|
||||
PsiSubstitutor rightSubstitutor = rightResult.getSubstitutor();
|
||||
PsiClass leftClass = leftResult.getElement();
|
||||
PsiClass rightClass = rightResult.getElement();
|
||||
@@ -945,7 +946,7 @@ public class TypeConversionUtil {
|
||||
PsiSubstitutor leftSubstitutor = leftResult.getSubstitutor();
|
||||
|
||||
if (!leftClass.getManager().areElementsEquivalent(leftClass, rightClass)) {
|
||||
rightSubstitutor = getSuperClassSubstitutor(leftClass, rightClass, rightSubstitutor);
|
||||
rightSubstitutor = superSubstitutor;
|
||||
rightClass = leftClass;
|
||||
}
|
||||
else if (!PsiUtil.typeParametersIterator(rightClass).hasNext()) return true;
|
||||
@@ -1063,7 +1064,7 @@ public class TypeConversionUtil {
|
||||
*
|
||||
* @return substitutor (never returns <code>null</code>)
|
||||
* @see PsiClass#isInheritor(PsiClass, boolean)
|
||||
* @see InheritanceUtil#isInheritorOrSelf(com.intellij.psi.PsiClass, com.intellij.psi.PsiClass, boolean)
|
||||
* @see InheritanceUtil#isInheritorOrSelf(PsiClass, PsiClass, boolean)
|
||||
*/
|
||||
@NotNull
|
||||
public static PsiSubstitutor getSuperClassSubstitutor(@NotNull PsiClass superClass,
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.psi.impl;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.JavaClassSupers;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class JavaClassSupersImpl extends JavaClassSupers {
|
||||
|
||||
@Nullable
|
||||
public PsiSubstitutor getSuperClassSubstitutor(@NotNull PsiClass superClass,
|
||||
@NotNull PsiClass derivedClass,
|
||||
@NotNull GlobalSearchScope scope,
|
||||
@NotNull PsiSubstitutor derivedSubstitutor) {
|
||||
if (isJavaLangObject(superClass)) return PsiSubstitutor.EMPTY;
|
||||
|
||||
return derivedClass instanceof PsiTypeParameter
|
||||
? processTypeParameter((PsiTypeParameter)derivedClass, scope, superClass, ContainerUtil.<PsiTypeParameter>newTroveSet(), derivedSubstitutor)
|
||||
: getSuperSubstitutorWithCaching(superClass, derivedClass, scope, derivedSubstitutor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiSubstitutor getSuperSubstitutorWithCaching(@NotNull PsiClass superClass,
|
||||
@NotNull PsiClass derivedClass,
|
||||
@NotNull GlobalSearchScope resolveScope,
|
||||
@NotNull PsiSubstitutor derivedSubstitutor) {
|
||||
PsiSubstitutor substitutor = ScopedClassHierarchy.getSuperClassSubstitutor(derivedClass, resolveScope, superClass);
|
||||
if (substitutor == null) return null;
|
||||
if (PsiUtil.isRawSubstitutor(derivedClass, derivedSubstitutor)) return createRawSubstitutor(superClass);
|
||||
|
||||
return composeSubstitutors(derivedSubstitutor, substitutor);
|
||||
}
|
||||
|
||||
static boolean isJavaLangObject(PsiClass psiClass) {
|
||||
return CommonClassNames.JAVA_LANG_OBJECT.equals(psiClass.getQualifiedName());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static PsiSubstitutor createRawSubstitutor(@NotNull PsiClass superClass) {
|
||||
return JavaPsiFacade.getElementFactory(superClass.getProject()).createRawSubstitutor(superClass);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiSubstitutor composeSubstitutors(PsiSubstitutor outer, PsiSubstitutor inner) {
|
||||
PsiSubstitutor answer = PsiSubstitutor.EMPTY;
|
||||
for (Map.Entry<PsiTypeParameter, PsiType> entry : inner.getSubstitutionMap().entrySet()) {
|
||||
answer = answer.put(entry.getKey(), outer.substitute(entry.getValue()));
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some type parameters (e.g. {@link com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable} change their supers at will,
|
||||
* so caching the hierarchy is impossible.
|
||||
*/
|
||||
@Nullable
|
||||
private static PsiSubstitutor processTypeParameter(PsiTypeParameter parameter,
|
||||
GlobalSearchScope scope,
|
||||
PsiClass superClass,
|
||||
Set<PsiTypeParameter> visited,
|
||||
PsiSubstitutor derivedSubstitutor) {
|
||||
if (parameter.getManager().areElementsEquivalent(parameter, superClass)) return PsiSubstitutor.EMPTY;
|
||||
if (!visited.add(parameter)) return null;
|
||||
|
||||
for (PsiClassType type : parameter.getExtendsListTypes()) {
|
||||
PsiClassType.ClassResolveResult result = type.resolveGenerics();
|
||||
PsiClass psiClass = result.getElement();
|
||||
if (psiClass == null) continue;
|
||||
|
||||
PsiSubstitutor answer;
|
||||
if (psiClass instanceof PsiTypeParameter) {
|
||||
answer = processTypeParameter((PsiTypeParameter)psiClass, scope, superClass, visited, derivedSubstitutor);
|
||||
if (answer != null) {
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
else {
|
||||
answer = getSuperSubstitutorWithCaching(superClass, psiClass, scope, result.getSubstitutor());
|
||||
if (answer != null) {
|
||||
return composeSubstitutors(derivedSubstitutor, answer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.psi.impl;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
class ScopedClassHierarchy {
|
||||
private static final TObjectHashingStrategy<PsiClass> CLASS_HASHING_STRATEGY = new TObjectHashingStrategy<PsiClass>() {
|
||||
@Override
|
||||
public int computeHashCode(PsiClass object) {
|
||||
return StringUtil.notNullize(object.getQualifiedName()).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(PsiClass o1, PsiClass o2) {
|
||||
return o1.getManager().areElementsEquivalent(o1, o2);
|
||||
}
|
||||
};
|
||||
private final Map<PsiClass, PsiClassType.ClassResolveResult> mySupersWithSubstitutors = ContainerUtil.newTroveMap(CLASS_HASHING_STRATEGY);
|
||||
|
||||
private ScopedClassHierarchy(PsiClass psiClass, GlobalSearchScope resolveScope) {
|
||||
PsiClassType type = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, PsiSubstitutor.EMPTY);
|
||||
visitTypes(resolveScope, PsiSubstitutor.EMPTY, type);
|
||||
}
|
||||
|
||||
private void visitTypes(GlobalSearchScope resolveScope, PsiSubstitutor substitutor, PsiType... types) {
|
||||
for (PsiType type : types) {
|
||||
type = PsiClassImplUtil.correctType(substitutor.substitute(type), resolveScope);
|
||||
if (!(type instanceof PsiClassType)) continue;
|
||||
|
||||
PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)type).resolveGenerics();
|
||||
PsiClass psiClass = resolveResult.getElement();
|
||||
if (psiClass == null || JavaClassSupersImpl.isJavaLangObject(psiClass) || mySupersWithSubstitutors.containsKey(psiClass)) continue;
|
||||
|
||||
mySupersWithSubstitutors.put(psiClass, resolveResult);
|
||||
|
||||
if (psiClass instanceof PsiAnonymousClass) {
|
||||
visitTypes(resolveScope, resolveResult.getSubstitutor(), ((PsiAnonymousClass)psiClass).getBaseClassType());
|
||||
}
|
||||
visitTypes(resolveScope, resolveResult.getSubstitutor(), psiClass.getExtendsListTypes());
|
||||
visitTypes(resolveScope, resolveResult.getSubstitutor(), psiClass.getImplementsListTypes());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ScopedClassHierarchy getHierarchy(@NotNull final PsiClass psiClass, @NotNull final GlobalSearchScope resolveScope) {
|
||||
return CachedValuesManager.getCachedValue(psiClass, new CachedValueProvider<Map<GlobalSearchScope, ScopedClassHierarchy>>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<Map<GlobalSearchScope, ScopedClassHierarchy>> compute() {
|
||||
Map<GlobalSearchScope, ScopedClassHierarchy> result = new ConcurrentFactoryMap<GlobalSearchScope, ScopedClassHierarchy>() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected ScopedClassHierarchy create(GlobalSearchScope resolveScope) {
|
||||
return new ScopedClassHierarchy(psiClass, resolveScope);
|
||||
}
|
||||
};
|
||||
return Result.create(result, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
|
||||
}
|
||||
}).get(resolveScope);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static PsiSubstitutor getSuperClassSubstitutor(@NotNull PsiClass derivedClass, @NotNull GlobalSearchScope scope, @NotNull PsiClass superClass) {
|
||||
PsiClassType.ClassResolveResult resolveResult = getHierarchy(derivedClass, scope).mySupersWithSubstitutors.get(superClass);
|
||||
if (resolveResult == null) return null;
|
||||
|
||||
PsiClass cachedClass = assertNotNull(resolveResult.getElement());
|
||||
PsiSubstitutor cachedSubstitutor = resolveResult.getSubstitutor();
|
||||
return cachedClass == superClass ? cachedSubstitutor : mirrorSubstitutor(superClass, cachedClass, cachedSubstitutor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiSubstitutor mirrorSubstitutor(@NotNull PsiClass from, @NotNull final PsiClass to, @NotNull PsiSubstitutor substitutor) {
|
||||
Iterator<PsiTypeParameter> baseParams = PsiUtil.typeParametersIterator(to);
|
||||
Iterator<PsiTypeParameter> candidateParams = PsiUtil.typeParametersIterator(from);
|
||||
|
||||
PsiSubstitutor answer = PsiSubstitutor.EMPTY;
|
||||
while (baseParams.hasNext()) {
|
||||
// if equivalent classes "from" and "to" have different number of type parameters, then treat "to" as a raw type
|
||||
if (!candidateParams.hasNext()) return JavaClassSupersImpl.createRawSubstitutor(to);
|
||||
|
||||
answer = answer.put(baseParams.next(), substitutor.substitute(candidateParams.next()));
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
}
|
||||
+14
-4
@@ -15,10 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.source.resolve.graphInference;
|
||||
|
||||
import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.PsiTypeParameter;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.light.LightTypeParameter;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -133,6 +130,19 @@ public class InferenceVariable extends LightTypeParameter {
|
||||
myThrownBound = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
|
||||
for (PsiType type : getBounds(InferenceBound.UPPER)) {
|
||||
PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(type);
|
||||
if (psiClass != null) {
|
||||
if (getManager().areElementsEquivalent(baseClass, psiClass)) return true;
|
||||
if (checkDeep && psiClass.isInheritor(baseClass, true)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.isInheritor(baseClass, checkDeep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEquivalentTo(PsiElement another) {
|
||||
return this == another || getDelegate() == another;
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import java.lang.Object;
|
||||
import java.lang.Override;
|
||||
import java.util.HashMap;
|
||||
|
||||
class Foo extends HashMap {
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
pu<caret>
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.idea.Bombed;
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
@@ -30,8 +29,6 @@ import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
|
||||
import com.intellij.testFramework.fixtures.*;
|
||||
import com.intellij.util.Consumer;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class MultipleJdksHighlightingTest extends UsefulTestCase {
|
||||
|
||||
private CodeInsightTestFixture myFixture;
|
||||
@@ -168,8 +165,8 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase {
|
||||
doTest3Modules();
|
||||
}
|
||||
|
||||
@Bombed(user = "peter,anna", year = 2015, month = Calendar.MAY, day = 15)
|
||||
public void testCloseableAutoCloseable() {
|
||||
IdeaTestUtil.setModuleLanguageLevel(myJava7Module, LanguageLevel.JDK_1_7);
|
||||
ModuleRootModificationUtil.addDependency(myJava7Module, myJava3Module);
|
||||
final String name = getTestName(false);
|
||||
myFixture.copyFileToProject("java3/p/" + name + ".java");
|
||||
|
||||
+14
-2
@@ -39,6 +39,8 @@ import com.intellij.openapi.command.undo.UndoManager
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter
|
||||
import com.intellij.openapi.editor.event.DocumentEvent
|
||||
import com.intellij.openapi.editor.ex.EditorEx
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.extensions.LoadingOrder
|
||||
@@ -152,10 +154,11 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase {
|
||||
|
||||
assertEquals 'iterable', lookup.currentItem.lookupString
|
||||
edt { myFixture.performEditorAction IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN }
|
||||
assertEquals 'iterable2', lookup.currentItem.lookupString
|
||||
assert lookup.currentItem.lookupString == 'iterable2'
|
||||
|
||||
type "r"
|
||||
myFixture.assertPreferredCompletionItems 2, "iter", "iterable", 'iterable2'
|
||||
assert lookup.items[0].lookupString == 'iter'
|
||||
assert lookup.currentItem.lookupString == 'iterable2'
|
||||
|
||||
}
|
||||
|
||||
@@ -950,6 +953,15 @@ class Foo {
|
||||
for (a1 in 0..actions) {
|
||||
for (a2 in 0..actions) {
|
||||
myFixture.configureByText("$a1 $a2 .java", src)
|
||||
myFixture.editor.document.addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
void documentChanged(DocumentEvent e) {
|
||||
if (e.newFragment.toString().contains("a")) {
|
||||
fail(e.toString())
|
||||
}
|
||||
super.documentChanged(e)
|
||||
}
|
||||
})
|
||||
myFixture.type 'i'
|
||||
joinSomething(a1)
|
||||
myFixture.type 'f'
|
||||
|
||||
+12
@@ -658,4 +658,16 @@ interface TxANotAnno {}
|
||||
assertPreferredItems 0, 'newLinkedSet1', 'newLinkedSet0', 'newLinkedSet2'
|
||||
}
|
||||
|
||||
public void testNoStatsInSuperInvocation() {
|
||||
checkPreferredItems 0, 'put', 'putAll'
|
||||
|
||||
myFixture.type('\n')
|
||||
assert myFixture.editor.document.text.contains("put")
|
||||
|
||||
myFixture.type(');\nsuper.')
|
||||
myFixture.completeBasic()
|
||||
|
||||
assertPreferredItems 0, 'get'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -286,7 +286,6 @@ public abstract class HTMLComposerImpl extends HTMLComposer {
|
||||
@Override
|
||||
public void appendListItem(StringBuffer buf, RefElement refElement) {
|
||||
startListItem(buf);
|
||||
buf.append(CLOSE_TAG);
|
||||
appendElementReference(buf, refElement, true);
|
||||
appendAdditionalListItemInfo(buf, refElement);
|
||||
doneListItem(buf);
|
||||
|
||||
@@ -58,7 +58,7 @@ public class BootstrapClassLoaderUtil extends ClassUtilCore {
|
||||
|
||||
UrlClassLoader.Builder builder = UrlClassLoader.build()
|
||||
.urls(filterClassPath(new ArrayList<URL>(classpath)))
|
||||
.allowLock(false)
|
||||
.allowLock()
|
||||
.usePersistentClasspathIndexForLocalClassDirectories()
|
||||
.useCache();
|
||||
if (Boolean.valueOf(System.getProperty(PROPERTY_ALLOW_BOOTSTRAP_RESOURCES, "true"))) {
|
||||
|
||||
@@ -446,6 +446,11 @@ public class IconUtil {
|
||||
}
|
||||
}
|
||||
|
||||
return createImageIcon(img);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JBImageIcon createImageIcon(@NotNull final BufferedImage img) {
|
||||
return new JBImageIcon(img) {
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
|
||||
@@ -21,9 +21,9 @@ import com.intellij.diff.chains.DiffRequestProducer;
|
||||
import com.intellij.diff.chains.DiffRequestProducerException;
|
||||
import com.intellij.diff.requests.*;
|
||||
import com.intellij.diff.tools.util.SoftHardCacheMap;
|
||||
import com.intellij.diff.util.DiffTaskQueue;
|
||||
import com.intellij.diff.util.DiffUserDataKeys;
|
||||
import com.intellij.diff.util.DiffUserDataKeysEx.ScrollToPolicy;
|
||||
import com.intellij.diff.util.WaitingBackgroundableTaskExecutor;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
@@ -33,9 +33,11 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.util.ProgressWindow;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import org.jetbrains.annotations.CalledInAwt;
|
||||
import org.jetbrains.annotations.CalledInBackground;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -51,7 +53,7 @@ public abstract class CacheDiffRequestChainProcessor extends DiffRequestProcesso
|
||||
@NotNull private final SoftHardCacheMap<DiffRequestProducer, DiffRequest> myRequestCache =
|
||||
new SoftHardCacheMap<DiffRequestProducer, DiffRequest>(5, 5);
|
||||
|
||||
@NotNull private final WaitingBackgroundableTaskExecutor myTaskExecutor = new WaitingBackgroundableTaskExecutor();
|
||||
@NotNull private final DiffTaskQueue myQueue = new DiffTaskQueue();
|
||||
|
||||
public CacheDiffRequestChainProcessor(@Nullable Project project, @NotNull DiffRequestChain requestChain) {
|
||||
super(project, requestChain);
|
||||
@@ -62,6 +64,7 @@ public abstract class CacheDiffRequestChainProcessor extends DiffRequestProcesso
|
||||
// Update
|
||||
//
|
||||
|
||||
@CalledInAwt
|
||||
public void updateRequest(final boolean force, @Nullable final ScrollToPolicy scrollToChangePolicy) {
|
||||
List<? extends DiffRequestProducer> requests = myRequestChain.getRequests();
|
||||
int index = myRequestChain.getIndex();
|
||||
@@ -78,12 +81,13 @@ public abstract class CacheDiffRequestChainProcessor extends DiffRequestProcesso
|
||||
return;
|
||||
}
|
||||
|
||||
myTaskExecutor.execute(
|
||||
new Convertor<ProgressIndicator, Runnable>() {
|
||||
myQueue.executeAndTryWait(
|
||||
new Function<ProgressIndicator, Runnable>() {
|
||||
@Override
|
||||
public Runnable convert(ProgressIndicator indicator) {
|
||||
public Runnable fun(ProgressIndicator indicator) {
|
||||
final DiffRequest request = loadRequest(producer, indicator);
|
||||
return new Runnable() {
|
||||
@CalledInAwt
|
||||
@Override
|
||||
public void run() {
|
||||
myRequestCache.put(producer, request);
|
||||
@@ -131,9 +135,10 @@ public abstract class CacheDiffRequestChainProcessor extends DiffRequestProcesso
|
||||
//
|
||||
|
||||
@Override
|
||||
@CalledInAwt
|
||||
protected void onDispose() {
|
||||
super.onDispose();
|
||||
myTaskExecutor.abort();
|
||||
Disposer.dispose(myQueue);
|
||||
myRequestCache.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -299,6 +299,7 @@ public abstract class DiffRequestProcessor implements Disposable {
|
||||
protected void onAfterNavigate() {
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
protected void onDispose() {
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.intellij.diff.FrameDiffTool;
|
||||
import com.intellij.diff.FrameDiffTool.DiffViewer;
|
||||
import com.intellij.diff.requests.ContentDiffRequest;
|
||||
import com.intellij.diff.tools.util.DiffDataKeys;
|
||||
import com.intellij.diff.util.WaitingBackgroundableTaskExecutor;
|
||||
import com.intellij.diff.util.DiffTaskQueue;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataProvider;
|
||||
@@ -31,8 +31,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.util.ProgressWindow;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
@@ -47,9 +46,7 @@ public abstract class DiffViewerBase implements DiffViewer, DataProvider {
|
||||
@NotNull protected final DiffContext myContext;
|
||||
@NotNull protected final ContentDiffRequest myRequest;
|
||||
|
||||
@NotNull private final WaitingBackgroundableTaskExecutor myTaskExecutor = new WaitingBackgroundableTaskExecutor();
|
||||
@NotNull private final Alarm myAlarm = new Alarm();
|
||||
|
||||
@NotNull private final DiffTaskQueue myTaskExecutor = new DiffTaskQueue();
|
||||
@NotNull private final AtomicBoolean myDisposed = new AtomicBoolean(false);
|
||||
|
||||
public DiffViewerBase(@NotNull DiffContext context, @NotNull ContentDiffRequest request) {
|
||||
@@ -75,15 +72,11 @@ public abstract class DiffViewerBase implements DiffViewer, DataProvider {
|
||||
public final void dispose() {
|
||||
if (!myDisposed.compareAndSet(false, true)) return;
|
||||
|
||||
Disposer.dispose(myAlarm);
|
||||
abortRediff();
|
||||
|
||||
onDispose();
|
||||
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
abortRediff();
|
||||
onDisposeAwt();
|
||||
}
|
||||
});
|
||||
@@ -92,14 +85,10 @@ public abstract class DiffViewerBase implements DiffViewer, DataProvider {
|
||||
@CalledInAwt
|
||||
public final void scheduleRediff() {
|
||||
if (myDisposed.get()) return;
|
||||
myTaskExecutor.abort();
|
||||
final int modificationStamp = myTaskExecutor.getModificationStamp();
|
||||
|
||||
myAlarm.cancelAllRequests();
|
||||
myAlarm.addRequest(new Runnable() {
|
||||
myTaskExecutor.abortAndSchedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (modificationStamp != myTaskExecutor.getModificationStamp()) return;
|
||||
rediff();
|
||||
}
|
||||
}, ProgressWindow.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS);
|
||||
@@ -127,10 +116,10 @@ public abstract class DiffViewerBase implements DiffViewer, DataProvider {
|
||||
|
||||
int waitMillis = trySync || tryRediffSynchronously() ? ProgressWindow.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS : 0;
|
||||
|
||||
myTaskExecutor.execute(
|
||||
new Convertor<ProgressIndicator, Runnable>() {
|
||||
myTaskExecutor.executeAndTryWait(
|
||||
new Function<ProgressIndicator, Runnable>() {
|
||||
@Override
|
||||
public Runnable convert(ProgressIndicator indicator) {
|
||||
public Runnable fun(ProgressIndicator indicator) {
|
||||
return performRediff(indicator);
|
||||
}
|
||||
},
|
||||
@@ -199,6 +188,7 @@ public abstract class DiffViewerBase implements DiffViewer, DataProvider {
|
||||
protected abstract Runnable performRediff(@NotNull ProgressIndicator indicator);
|
||||
|
||||
protected void onDispose() {
|
||||
Disposer.dispose(myTaskExecutor);
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
|
||||
+23
-43
@@ -21,7 +21,7 @@ import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.EmptyRunnable;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.Function;
|
||||
import org.jetbrains.annotations.CalledInAwt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -34,59 +34,38 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
* Executor to perform <possibly> long operations on pooled thread
|
||||
* Is is used to reduce blinking, in case of fast end of background task.
|
||||
*/
|
||||
public class WaitingBackgroundableTaskExecutor {
|
||||
public class BackgroundTaskUtil {
|
||||
private static final Runnable TOO_SLOW_OPERATION = new EmptyRunnable();
|
||||
|
||||
private int myModificationStamp = 0;
|
||||
@Nullable private ProgressIndicator myProgressIndicator;
|
||||
|
||||
@CalledInAwt
|
||||
public int getModificationStamp() {
|
||||
return myModificationStamp;
|
||||
@NotNull
|
||||
public static ProgressIndicator executeAndTryWait(@NotNull final Function<ProgressIndicator, Runnable> backgroundTask,
|
||||
@Nullable final Runnable onSlowAction,
|
||||
final int waitMillis) {
|
||||
return executeAndTryWait(backgroundTask, onSlowAction, waitMillis, false);
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public void abort() {
|
||||
if (myProgressIndicator != null) {
|
||||
myProgressIndicator.cancel();
|
||||
myProgressIndicator = null;
|
||||
myModificationStamp++;
|
||||
}
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public void execute(@NotNull final Convertor<ProgressIndicator, Runnable> backgroundTask,
|
||||
@Nullable final Runnable onSlowAction,
|
||||
final int waitMillis) {
|
||||
execute(backgroundTask, onSlowAction, waitMillis, false);
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public void execute(@NotNull final Convertor<ProgressIndicator, Runnable> backgroundTask,
|
||||
@Nullable final Runnable onSlowAction,
|
||||
final int waitMillis,
|
||||
final boolean forceEDT) {
|
||||
abort();
|
||||
|
||||
myModificationStamp++;
|
||||
final int modificationStamp = myModificationStamp;
|
||||
|
||||
@NotNull
|
||||
public static ProgressIndicator executeAndTryWait(@NotNull final Function<ProgressIndicator, Runnable> backgroundTask,
|
||||
@Nullable final Runnable onSlowAction,
|
||||
final int waitMillis,
|
||||
final boolean forceEDT) {
|
||||
final ModalityState modality = ModalityState.current();
|
||||
myProgressIndicator = new EmptyProgressIndicator() {
|
||||
final ProgressIndicator indicator = new EmptyProgressIndicator() {
|
||||
@NotNull
|
||||
@Override
|
||||
public ModalityState getModalityState() {
|
||||
return modality;
|
||||
}
|
||||
};
|
||||
final ProgressIndicator indicator = myProgressIndicator;
|
||||
|
||||
final Semaphore semaphore = new Semaphore(0);
|
||||
final AtomicReference<Runnable> resultRef = new AtomicReference<Runnable>();
|
||||
|
||||
if (forceEDT) {
|
||||
Runnable result = backgroundTask.convert(indicator);
|
||||
finish(result, modificationStamp, indicator);
|
||||
Runnable callback = backgroundTask.fun(indicator);
|
||||
finish(callback, indicator);
|
||||
}
|
||||
else {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@@ -95,18 +74,18 @@ public class WaitingBackgroundableTaskExecutor {
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Runnable result = backgroundTask.convert(indicator);
|
||||
final Runnable callback = backgroundTask.fun(indicator);
|
||||
|
||||
if (indicator.isCanceled()) {
|
||||
semaphore.release();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!resultRef.compareAndSet(null, result)) {
|
||||
if (!resultRef.compareAndSet(null, callback)) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
finish(result, modificationStamp, indicator);
|
||||
finish(callback, indicator);
|
||||
}
|
||||
}, modality);
|
||||
}
|
||||
@@ -123,19 +102,20 @@ public class WaitingBackgroundableTaskExecutor {
|
||||
}
|
||||
if (!resultRef.compareAndSet(null, TOO_SLOW_OPERATION)) {
|
||||
// update presentation in the same thread to reduce blinking, caused by 'invokeLater' and fast background operation
|
||||
finish(resultRef.get(), modificationStamp, indicator);
|
||||
finish(resultRef.get(), indicator);
|
||||
}
|
||||
else {
|
||||
if (onSlowAction != null) onSlowAction.run();
|
||||
}
|
||||
}
|
||||
|
||||
return indicator;
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
private void finish(@NotNull Runnable result, int modificationStamp, @NotNull ProgressIndicator indicator) {
|
||||
private static void finish(@NotNull Runnable result, @NotNull ProgressIndicator indicator) {
|
||||
if (indicator.isCanceled()) return;
|
||||
if (myModificationStamp != modificationStamp) return;
|
||||
|
||||
result.run();
|
||||
indicator.stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.diff.util;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.Function;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class DiffTaskQueue implements Disposable {
|
||||
@NotNull private final Object LOCK = new Object();
|
||||
@NotNull private final Alarm myAlarm = new Alarm();
|
||||
|
||||
private boolean myDisposed;
|
||||
@NotNull private final AtomicReference<ProgressIndicator> myProgressIndicator = new AtomicReference<ProgressIndicator>();
|
||||
|
||||
@CalledInAny
|
||||
public void dispose() {
|
||||
// if EDT is awaiting for background progress in executeAndTryWait - it holds LOCK.
|
||||
// so we want to try cancel indicator before getting the lock.
|
||||
cancelProgress();
|
||||
synchronized (LOCK) {
|
||||
if (myDisposed) return;
|
||||
myDisposed = true;
|
||||
cancelProgress();
|
||||
Disposer.dispose(myAlarm);
|
||||
}
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public void abort() {
|
||||
synchronized (LOCK) {
|
||||
cancelProgress();
|
||||
myAlarm.cancelAllRequests();
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelProgress() {
|
||||
ProgressIndicator indicator = myProgressIndicator.getAndSet(null);
|
||||
if (indicator != null) indicator.cancel();
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public void abortAndSchedule(@NotNull final Runnable task, int millis) {
|
||||
synchronized (LOCK) {
|
||||
if (myDisposed) return;
|
||||
abort();
|
||||
|
||||
myAlarm.addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (LOCK) {
|
||||
if (myDisposed) return;
|
||||
}
|
||||
task.run();
|
||||
}
|
||||
}, millis);
|
||||
}
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public void executeAndTryWait(@NotNull final Function<ProgressIndicator, Runnable> backgroundTask,
|
||||
@Nullable final Runnable onSlowAction,
|
||||
final int waitMillis) {
|
||||
executeAndTryWait(backgroundTask, onSlowAction, waitMillis, false);
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public void executeAndTryWait(@NotNull final Function<ProgressIndicator, Runnable> backgroundTask,
|
||||
@Nullable final Runnable onSlowAction,
|
||||
final int waitMillis,
|
||||
final boolean forceEDT) {
|
||||
synchronized (LOCK) {
|
||||
if (myDisposed) return;
|
||||
abort();
|
||||
|
||||
Function<ProgressIndicator, Runnable> function = new Function<ProgressIndicator, Runnable>() {
|
||||
@Override
|
||||
@CalledInBackground
|
||||
public Runnable fun(final ProgressIndicator indicator) {
|
||||
final Runnable callback = backgroundTask.fun(indicator);
|
||||
return new Runnable() {
|
||||
@Override
|
||||
@CalledInAwt
|
||||
public void run() {
|
||||
synchronized (LOCK) {
|
||||
if (myDisposed) return;
|
||||
indicator.checkCanceled();
|
||||
}
|
||||
callback.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
myProgressIndicator.set(BackgroundTaskUtil.executeAndTryWait(function, onSlowAction, waitMillis, forceEDT));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,9 +47,6 @@ public interface RepositoryManager<T extends Repository> {
|
||||
@Nullable
|
||||
T getRepositoryForFile(@NotNull VirtualFile file);
|
||||
|
||||
@Nullable
|
||||
T getRepositoryForFile(@NotNull VirtualFile file, boolean updateIfNeeded);
|
||||
|
||||
/**
|
||||
* Returns the {@link Repository} which the given file belongs to, or {@code null} if the file is not under any Git ot Hg repository.
|
||||
*/
|
||||
|
||||
@@ -29,9 +29,12 @@ public abstract class AbstractRepositoryManager<T extends Repository>
|
||||
@Override
|
||||
@Nullable
|
||||
public T getRepositoryForRoot(@Nullable VirtualFile root) {
|
||||
Repository repository = myGlobalRepositoryManager.getRepositoryForRoot(root, true);
|
||||
//noinspection unchecked
|
||||
return isRootValid(repository) ? (T)repository : null;
|
||||
return validateAndGetRepository(myGlobalRepositoryManager.getRepositoryForRoot(root));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T getRepositoryForRootQuick(@Nullable VirtualFile root) {
|
||||
return validateAndGetRepository(myGlobalRepositoryManager.getRepositoryForRootQuick(root));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,15 +55,7 @@ public abstract class AbstractRepositoryManager<T extends Repository>
|
||||
@Override
|
||||
@Nullable
|
||||
public T getRepositoryForFile(@NotNull VirtualFile file) {
|
||||
return getRepositoryForFile(file, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public T getRepositoryForFile(@NotNull VirtualFile file, boolean updateIfNeeded) {
|
||||
Repository repository = myGlobalRepositoryManager.getRepositoryForFile(file, updateIfNeeded);
|
||||
//noinspection unchecked
|
||||
return repository != null && myVcs.equals(repository.getVcs()) ? (T)repository : null;
|
||||
return validateAndGetRepository(myGlobalRepositoryManager.getRepositoryForFile(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,9 +98,11 @@ public abstract class AbstractRepositoryManager<T extends Repository>
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isRootValid(@Nullable Repository repository) {
|
||||
if (repository == null || !myVcs.equals(repository.getVcs())) return false;
|
||||
@Nullable
|
||||
private T validateAndGetRepository(@Nullable Repository repository) {
|
||||
if (repository == null || !myVcs.equals(repository.getVcs())) return null;
|
||||
VirtualFile vcsDir = repository.getRoot().findChild(myRepoDirName);
|
||||
return vcsDir != null && vcsDir.exists();
|
||||
//noinspection unchecked
|
||||
return vcsDir != null && vcsDir.exists() ? (T)repository : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,17 +80,22 @@ public class VcsRepositoryManager extends AbstractProjectComponent implements Di
|
||||
|
||||
@Nullable
|
||||
public Repository getRepositoryForFile(@NotNull VirtualFile file) {
|
||||
return getRepositoryForFile(file, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Repository getRepositoryForFile(@NotNull VirtualFile file, boolean updateIfNeeded) {
|
||||
final VcsRoot vcsRoot = myVcsManager.getVcsRootObjectFor(file);
|
||||
return vcsRoot != null ? getRepositoryForRoot(vcsRoot.getPath(), updateIfNeeded) : null;
|
||||
return vcsRoot != null ? getRepositoryForRoot(vcsRoot.getPath()) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Repository getRepositoryForRoot(@Nullable VirtualFile root, boolean updateIfNeeded) {
|
||||
public Repository getRepositoryForRootQuick(@Nullable VirtualFile root) {
|
||||
return getRepositoryForRoot(root, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Repository getRepositoryForRoot(@Nullable VirtualFile root) {
|
||||
return getRepositoryForRoot(root, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Repository getRepositoryForRoot(@Nullable VirtualFile root, boolean updateIfNeeded) {
|
||||
if (root == null) return null;
|
||||
Repository result;
|
||||
try {
|
||||
|
||||
@@ -120,12 +120,12 @@ public class VcsRepositoryManagerTest extends UsefulTestCase {
|
||||
|
||||
public void testRepositoryInfoReadingWhileModifying() throws Exception {
|
||||
final VirtualFile repositoryFile = createExternalRepository();
|
||||
assertNotNull(myGlobalRepositoryManager.getRepositoryForRoot(repositoryFile, true));
|
||||
assertNotNull(myGlobalRepositoryManager.getRepositoryForRoot(repositoryFile));
|
||||
|
||||
FutureTask<Repository> readExistingRepo = new FutureTask<Repository>(new Callable<Repository>() {
|
||||
@Override
|
||||
public Repository call() throws Exception {
|
||||
return myGlobalRepositoryManager.getRepositoryForRoot(repositoryFile, true);
|
||||
return myGlobalRepositoryManager.getRepositoryForRoot(repositoryFile);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.patch.CreatePatchConfigurationPanel;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.ui.components.JBLayeredPane;
|
||||
@@ -494,9 +495,10 @@ public abstract class HistoryDialog<T extends HistoryDialogModel> extends FrameW
|
||||
|
||||
private boolean showAsDialog(CreatePatchConfigurationPanel p) {
|
||||
final DialogBuilder b = new DialogBuilder(myProject);
|
||||
b.setPreferredFocusComponent(p.getPreferredFocusComponent());
|
||||
JComponent createPatchPanel = p.getPanel();
|
||||
b.setPreferredFocusComponent(IdeFocusTraversalPolicy.getPreferredFocusedComponent(createPatchPanel));
|
||||
b.setTitle(message("create.patch.dialog.title"));
|
||||
b.setCenterPanel(p.getPanel());
|
||||
b.setCenterPanel(createPatchPanel);
|
||||
p.installOkEnabledListener(new Consumer<Boolean>() {
|
||||
public void consume(final Boolean aBoolean) {
|
||||
b.setOkActionEnabled(aBoolean);
|
||||
|
||||
+4
-3
@@ -41,14 +41,15 @@ public class TreeTableCellRenderer implements TableCellRenderer, ClientPropertyH
|
||||
|
||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
||||
int modelRow = table.convertRowIndexToModel(row);
|
||||
final boolean lineHasFocus = table.hasFocus();
|
||||
|
||||
if (myTreeCellRenderer != null)
|
||||
myTree.setCellRenderer(myTreeCellRenderer);
|
||||
if (isSelected){
|
||||
myTree.setBackground(table.getSelectionBackground());
|
||||
myTree.setBackground(lineHasFocus ? table.getSelectionBackground() : UIUtil.getTreeUnfocusedSelectionBackground());
|
||||
myTree.setForeground(table.getSelectionForeground());
|
||||
}
|
||||
else{
|
||||
else {
|
||||
myTree.setBackground(table.getBackground());
|
||||
myTree.setForeground(table.getForeground());
|
||||
}
|
||||
@@ -60,7 +61,7 @@ public class TreeTableCellRenderer implements TableCellRenderer, ClientPropertyH
|
||||
final Object treeObject = myTree.getPathForRow(modelRow).getLastPathComponent();
|
||||
boolean leaf = myTree.getModel().isLeaf(treeObject);
|
||||
final boolean expanded = myTree.isExpanded(modelRow);
|
||||
Component component = myTree.getCellRenderer().getTreeCellRendererComponent(myTree, treeObject, isSelected, expanded, leaf, modelRow, hasFocus);
|
||||
Component component = myTree.getCellRenderer().getTreeCellRendererComponent(myTree, treeObject, isSelected, expanded, leaf, modelRow, lineHasFocus);
|
||||
if (component instanceof JComponent) {
|
||||
table.setToolTipText(((JComponent)component).getToolTipText());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -556,7 +556,7 @@ public class FileWatcher {
|
||||
case CREATE:
|
||||
case DELETE:
|
||||
for (String p : paths) {
|
||||
myDirtyPaths.dirtyPaths.add(p);
|
||||
myDirtyPaths.dirtyPathsRecursive.add(p);
|
||||
String parentPath = new File(p).getParent();
|
||||
if (parentPath != null) {
|
||||
myDirtyPaths.dirtyPaths.add(parentPath);
|
||||
|
||||
@@ -714,6 +714,33 @@ public class FileWatcherTest extends PlatformLangTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testDisplacementByIsomorphicTree() throws Exception {
|
||||
File top = createTestDir("top");
|
||||
File up = createTestDir(top, "up");
|
||||
File middle = createTestDir(up, "middle");
|
||||
File file = createTestFile(middle, "file.txt", "original content");
|
||||
File up_copy = new File(top, "up_copy");
|
||||
FileUtil.copyDir(up, up_copy);
|
||||
FileUtil.writeToFile(file, "new content");
|
||||
|
||||
VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
|
||||
assertNotNull(vFile);
|
||||
assertEquals("new content", VfsUtilCore.loadText(vFile));
|
||||
|
||||
LocalFileSystem.WatchRequest request = watch(up);
|
||||
try {
|
||||
myAccept = true;
|
||||
FileUtil.rename(up, new File(top, "up.bak"));
|
||||
FileUtil.rename(up_copy, up);
|
||||
assertEvent(VFileContentChangeEvent.class, file.getPath());
|
||||
assertTrue(vFile.isValid());
|
||||
assertEquals("original content", VfsUtilCore.loadText(vFile));
|
||||
}
|
||||
finally {
|
||||
unwatch(request);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private LocalFileSystem.WatchRequest watch(File watchFile) {
|
||||
|
||||
@@ -130,7 +130,8 @@ public class CompositeException extends Exception {
|
||||
sb.append(line);
|
||||
|
||||
line = exceptionProcessor.fun(exception);
|
||||
if (!line.endsWith("\n")) line += '\n';
|
||||
if (line == null) line = "null\n";
|
||||
else if (!line.endsWith("\n")) line += '\n';
|
||||
stringProcessor.process(line);
|
||||
sb.append(line);
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
<orderEntry type="module" module-name="platform-impl" exported="" />
|
||||
<orderEntry type="library" exported="" name="Log4J" level="project" />
|
||||
<orderEntry type="module" module-name="vcs-api" exported="" />
|
||||
<orderEntry type="module" module-name="lvcs-impl" />
|
||||
<orderEntry type="module" module-name="lvcs-impl" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="tests_bootstrap" />
|
||||
<orderEntry type="module" module-name="resources-en" scope="RUNTIME" />
|
||||
<orderEntry type="library" exported="" scope="TEST" name="Mocks" level="project" />
|
||||
<orderEntry type="module" module-name="java-runtime" exported="" />
|
||||
<orderEntry type="module" module-name="vcs-impl" />
|
||||
<orderEntry type="module" module-name="vcs-impl" scope="RUNTIME" />
|
||||
<orderEntry type="library" exported="" name="Groovy" level="project" />
|
||||
<orderEntry type="module" module-name="platform-resources" exported="" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="dom-impl" exported="" scope="RUNTIME" />
|
||||
@@ -27,5 +27,4 @@
|
||||
<orderEntry type="module" module-name="images" exported="" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="RegExpSupport" exported="" scope="RUNTIME" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
</module>
|
||||
@@ -80,9 +80,17 @@ public class Diff {
|
||||
changes = patienceIntLCS.getChanges();
|
||||
}
|
||||
else {
|
||||
IntLCS intLCS = new IntLCS(discarded[0], discarded[1]);
|
||||
intLCS.execute();
|
||||
changes = intLCS.getChanges();
|
||||
try {
|
||||
IntLCS intLCS = new IntLCS(discarded[0], discarded[1]);
|
||||
intLCS.execute();
|
||||
changes = intLCS.getChanges();
|
||||
}
|
||||
catch (FilesTooBigForDiffException e) {
|
||||
PatienceIntLCS patienceIntLCS = new PatienceIntLCS(discarded[0], discarded[1]);
|
||||
patienceIntLCS.failOnSmallSizeReduction();
|
||||
patienceIntLCS.execute();
|
||||
changes = patienceIntLCS.getChanges();
|
||||
}
|
||||
}
|
||||
|
||||
reindexer.reindex(changes, builder);
|
||||
|
||||
@@ -29,6 +29,8 @@ public class PatienceIntLCS {
|
||||
private final BitSet myChanges1;
|
||||
private final BitSet myChanges2;
|
||||
|
||||
private boolean myFailOnSmallReduction;
|
||||
|
||||
public PatienceIntLCS(int[] first, int[] second) {
|
||||
this(first, second, 0, first.length, 0, second.length, new BitSet(first.length), new BitSet(second.length));
|
||||
}
|
||||
@@ -45,6 +47,10 @@ public class PatienceIntLCS {
|
||||
myChanges2 = changes2;
|
||||
}
|
||||
|
||||
public void failOnSmallSizeReduction() {
|
||||
myFailOnSmallReduction = true;
|
||||
}
|
||||
|
||||
public void execute() throws FilesTooBigForDiffException {
|
||||
if (myCount1 == 0 && myCount2 == 0) {
|
||||
return;
|
||||
@@ -71,6 +77,7 @@ public class PatienceIntLCS {
|
||||
int[][] matching = uniqueLCS.execute();
|
||||
|
||||
if (matching == null) {
|
||||
checkReduction(count1, count2);
|
||||
IntLCS intLCS = new IntLCS(myFirst, mySecond, start1, count1, start2, count2, myChanges1, myChanges2);
|
||||
intLCS.execute();
|
||||
}
|
||||
@@ -79,8 +86,12 @@ public class PatienceIntLCS {
|
||||
int matched = matching[0].length;
|
||||
assert matched > 0;
|
||||
|
||||
c1 = matching[0][0];
|
||||
c2 = matching[1][0];
|
||||
|
||||
checkReduction(c1, c2);
|
||||
PatienceIntLCS patienceDiff =
|
||||
new PatienceIntLCS(myFirst, mySecond, start1, matching[0][0], start2, matching[1][0], myChanges1, myChanges2);
|
||||
new PatienceIntLCS(myFirst, mySecond, start1, c1, start2, c2, myChanges1, myChanges2);
|
||||
patienceDiff.execute();
|
||||
|
||||
for (int i = 1; i < matching[0].length; i++) {
|
||||
@@ -91,6 +102,7 @@ public class PatienceIntLCS {
|
||||
c2 = matching[1][i] - s2;
|
||||
|
||||
if (c1 > 0 || c2 > 0) {
|
||||
checkReduction(c1, c2);
|
||||
patienceDiff = new PatienceIntLCS(myFirst, mySecond, start1 + s1, c1, start2 + s2, c2, myChanges1, myChanges2);
|
||||
patienceDiff.execute();
|
||||
}
|
||||
@@ -113,6 +125,7 @@ public class PatienceIntLCS {
|
||||
c2 = count2 - s2;
|
||||
}
|
||||
|
||||
checkReduction(c1, c2);
|
||||
patienceDiff = new PatienceIntLCS(myFirst, mySecond, start1 + s1, c1, start2 + s2, c2, myChanges1, myChanges2);
|
||||
patienceDiff.execute();
|
||||
}
|
||||
@@ -147,4 +160,11 @@ public class PatienceIntLCS {
|
||||
public BitSet[] getChanges() {
|
||||
return new BitSet[]{myChanges1, myChanges2};
|
||||
}
|
||||
|
||||
private void checkReduction(int count1, int count2) throws FilesTooBigForDiffException {
|
||||
if (!myFailOnSmallReduction) return;
|
||||
if (count1 * 2 < myCount1) return;
|
||||
if (count2 * 2 < myCount2) return;
|
||||
throw new FilesTooBigForDiffException(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ package com.intellij.util.lang;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import sun.misc.Resource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.net.URL;
|
||||
@@ -30,15 +30,18 @@ import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
class JarLoader extends Loader {
|
||||
private final URL myURL;
|
||||
private final File myCanonicalFile;
|
||||
private final boolean myCanLockJar; // true implies that the zipfile will not be modified in the lifetime of the JarLoader
|
||||
private SoftReference<JarMemoryLoader> myMemoryLoader;
|
||||
private volatile SoftReference<ZipFile> myZipFileSoftReference; // Used only when myCanLockJar==true
|
||||
|
||||
// todo drop unused parameter
|
||||
JarLoader(URL url, @SuppressWarnings("unused") boolean canLockJar, int index, boolean preloadJarContents) throws IOException {
|
||||
super(new URL(URLUtil.JAR_PROTOCOL, "", -1, url + "!/"), index);
|
||||
myURL = url;
|
||||
super(new URL("jar", "", -1, url + "!/"), index);
|
||||
|
||||
ZipFile zipFile = new ZipFile(getFileUrl());
|
||||
myCanonicalFile = new File(FileUtil.unquote(url.getFile())).getCanonicalFile();
|
||||
myCanLockJar = canLockJar;
|
||||
|
||||
ZipFile zipFile = getZipFile(); // IOException from opening is propagated to caller if zip file isn't valid,
|
||||
try {
|
||||
if (preloadJarContents) {
|
||||
JarMemoryLoader loader = JarMemoryLoader.load(zipFile, getBaseURL());
|
||||
@@ -48,18 +51,14 @@ class JarLoader extends Loader {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
zipFile.close();
|
||||
releaseZipFile(zipFile);
|
||||
}
|
||||
}
|
||||
|
||||
private String getFileUrl() throws IOException {
|
||||
return FileUtil.unquote(myURL.getFile());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ClasspathCache.LoaderData buildData() throws IOException {
|
||||
ZipFile zipFile = new ZipFile(getFileUrl());
|
||||
ZipFile zipFile = getZipFile();
|
||||
try {
|
||||
ClasspathCache.LoaderData loaderData = new ClasspathCache.LoaderData();
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
@@ -72,21 +71,21 @@ class JarLoader extends Loader {
|
||||
return loaderData;
|
||||
}
|
||||
finally {
|
||||
zipFile.close();
|
||||
releaseZipFile(zipFile);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
Resource getResource(String name, boolean flag) {
|
||||
JarMemoryLoader loader = com.intellij.reference.SoftReference.dereference(myMemoryLoader);
|
||||
JarMemoryLoader loader = myMemoryLoader != null? myMemoryLoader.get() : null;
|
||||
if (loader != null) {
|
||||
Resource resource = loader.getResource(name);
|
||||
if (resource != null) return resource;
|
||||
}
|
||||
|
||||
try {
|
||||
ZipFile zipFile = new ZipFile(getFileUrl());
|
||||
ZipFile zipFile = getZipFile();
|
||||
try {
|
||||
ZipEntry entry = zipFile.getEntry(name);
|
||||
if (entry != null) {
|
||||
@@ -94,18 +93,58 @@ class JarLoader extends Loader {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
zipFile.close();
|
||||
releaseZipFile(zipFile);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.getInstance(JarLoader.class).error("url: " + myURL, e);
|
||||
error("file: " + myCanonicalFile, e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void error(String message, Throwable t) {
|
||||
//Logger.getLogger(JarLoader.class.getName()).log(Level.SEVERE, message, t);
|
||||
Logger.getInstance(JarLoader.class).error(message, t);
|
||||
}
|
||||
|
||||
private void releaseZipFile(ZipFile zipFile) throws IOException {
|
||||
// Closing of zip file when myCanLockJar=true happens in ZipFile.finalize
|
||||
if (!myCanLockJar) {
|
||||
zipFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ZipFile getZipFile() throws IOException {
|
||||
// This code is executed at least 100K times (O(number of classes needed to load)) and it takes considerable time to open ZipFile's
|
||||
// such number of times so we store reference to ZipFile if we allowed to lock the file (assume it isn't changed)
|
||||
if (myCanLockJar) {
|
||||
SoftReference<ZipFile> zipFileSoftReference = myZipFileSoftReference;
|
||||
if(zipFileSoftReference != null) {
|
||||
ZipFile existingZipFile = zipFileSoftReference.get();
|
||||
if (existingZipFile != null) return existingZipFile;
|
||||
}
|
||||
synchronized (ourLock) {
|
||||
zipFileSoftReference = myZipFileSoftReference;
|
||||
if(zipFileSoftReference != null) {
|
||||
ZipFile existingZipFile = zipFileSoftReference.get();
|
||||
if (existingZipFile != null) return existingZipFile;
|
||||
}
|
||||
// ZipFile's native implementation (ZipFile.c, zip_util.c) has path -> file descriptor cache
|
||||
ZipFile zipFile = new ZipFile(myCanonicalFile);
|
||||
myZipFileSoftReference = new SoftReference<ZipFile>(zipFile);
|
||||
return zipFile;
|
||||
}
|
||||
} else {
|
||||
return new ZipFile(myCanonicalFile);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JarLoader [" + myURL + "]";
|
||||
return "JarLoader [" + myCanonicalFile + "]";
|
||||
}
|
||||
|
||||
private static final Object ourLock = new Object();
|
||||
}
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package com.intellij.util.lang;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.containers.hash.HashMap;
|
||||
import com.intellij.util.io.zip.ZipShort;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import sun.misc.Resource;
|
||||
|
||||
@@ -26,6 +24,7 @@ import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
@@ -64,8 +63,8 @@ public class JarMemoryLoader {
|
||||
ZipEntry sizeEntry = entries.nextElement();
|
||||
if (sizeEntry == null || !sizeEntry.getName().equals(SIZE_ENTRY)) return null;
|
||||
|
||||
byte[] bytes = FileUtil.loadBytes(zipFile.getInputStream(sizeEntry), 2);
|
||||
int size = ZipShort.getValue(bytes);
|
||||
byte[] bytes = FileUtilRt.loadBytes(zipFile.getInputStream(sizeEntry), 2);
|
||||
int size = ((bytes[1] & 0xFF) << 8) + (bytes[0] & 0xFF);
|
||||
|
||||
JarMemoryLoader loader = new JarMemoryLoader();
|
||||
for (int i = 0; i < size && entries.hasMoreElements(); i++) {
|
||||
|
||||
@@ -38,6 +38,7 @@ import java.awt.event.MouseListener;
|
||||
*/
|
||||
public class WideSelectionTreeUI extends BasicTreeUI {
|
||||
public static final String TREE_TABLE_TREE_KEY = "TreeTableTree";
|
||||
public static final String NO_SELECTION_PAINTING_DARK = "NO_SELECTION_PAINTING_DARK";
|
||||
|
||||
@NonNls public static final String SOURCE_LIST_CLIENT_PROPERTY = "mac.ui.source.list";
|
||||
@NonNls public static final String STRIPED_CLIENT_PROPERTY = "mac.ui.striped";
|
||||
@@ -361,7 +362,8 @@ public class WideSelectionTreeUI extends BasicTreeUI {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (selected && (UIUtil.isUnderAquaBasedLookAndFeel() || UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF())) {
|
||||
if (selected && (UIUtil.isUnderAquaBasedLookAndFeel() || UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF())
|
||||
&& ! Boolean.TRUE.equals(tree.getClientProperty(NO_SELECTION_PAINTING_DARK))) {
|
||||
Color bg = UIUtil.getTreeSelectionBackground(tree.hasFocus() || Boolean.TRUE.equals(tree.getClientProperty(TREE_TABLE_TREE_KEY)));
|
||||
|
||||
if (myWideSelectionCondition.value(row)) {
|
||||
|
||||
@@ -19,9 +19,9 @@ import com.intellij.diff.chains.DiffRequestProducerException;
|
||||
import com.intellij.diff.impl.DiffRequestProcessor;
|
||||
import com.intellij.diff.requests.*;
|
||||
import com.intellij.diff.tools.util.SoftHardCacheMap;
|
||||
import com.intellij.diff.util.DiffTaskQueue;
|
||||
import com.intellij.diff.util.DiffUserDataKeys;
|
||||
import com.intellij.diff.util.DiffUserDataKeysEx.ScrollToPolicy;
|
||||
import com.intellij.diff.util.WaitingBackgroundableTaskExecutor;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
@@ -31,10 +31,11 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.util.ProgressWindow;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vcs.changes.actions.diff.ChangeDiffRequestProducer;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -48,7 +49,7 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor {
|
||||
|
||||
@Nullable private Change myCurrentChange;
|
||||
|
||||
@NotNull private final WaitingBackgroundableTaskExecutor myTaskExecutor = new WaitingBackgroundableTaskExecutor();
|
||||
@NotNull private final DiffTaskQueue myQueue = new DiffTaskQueue();
|
||||
|
||||
public CacheChangeProcessor(@NotNull Project project) {
|
||||
super(project);
|
||||
@@ -74,21 +75,25 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor {
|
||||
// Update
|
||||
//
|
||||
|
||||
@CalledInAwt
|
||||
public void updateRequest(final boolean force, @Nullable final ScrollToPolicy scrollToChangePolicy) {
|
||||
final Change change = myCurrentChange;
|
||||
|
||||
DiffRequest cachedRequest = loadRequestFast(change);
|
||||
if (cachedRequest != null) {
|
||||
applyRequest(cachedRequest, force, scrollToChangePolicy);
|
||||
return;
|
||||
}
|
||||
|
||||
myTaskExecutor.execute(
|
||||
new Convertor<ProgressIndicator, Runnable>() {
|
||||
// TODO: check if current loading change is the same as we want to load now? (and not interrupt loading)
|
||||
myQueue.executeAndTryWait(
|
||||
new Function<ProgressIndicator, Runnable>() {
|
||||
@Override
|
||||
public Runnable convert(ProgressIndicator indicator) {
|
||||
public Runnable fun(ProgressIndicator indicator) {
|
||||
final DiffRequest request = loadRequest(change, indicator);
|
||||
return new Runnable() {
|
||||
@Override
|
||||
@CalledInAwt
|
||||
public void run() {
|
||||
myRequestCache.put(change, Pair.create(change, request));
|
||||
applyRequest(request, force, scrollToChangePolicy);
|
||||
@@ -107,6 +112,7 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@CalledInAwt
|
||||
@Contract("null -> !null")
|
||||
protected DiffRequest loadRequestFast(@Nullable Change change) {
|
||||
if (change == null) return NoDiffRequest.INSTANCE;
|
||||
@@ -152,9 +158,10 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor {
|
||||
//
|
||||
|
||||
@Override
|
||||
@CalledInAwt
|
||||
protected void onDispose() {
|
||||
super.onDispose();
|
||||
myTaskExecutor.abort();
|
||||
Disposer.dispose(myQueue);
|
||||
myRequestCache.clear();
|
||||
}
|
||||
|
||||
|
||||
+1
-14
@@ -34,7 +34,6 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.VcsConfiguration;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ui.ComplexFocusedComponentWrapper;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -235,20 +234,8 @@ public class CreatePatchConfigurationPanel {
|
||||
return myIncludedChanges;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JComponent getPanel() {
|
||||
return new ComplexFocusedComponentWrapper(
|
||||
!myIncludeBaseRevisionTextCheckBox.isVisible() || myChanges.isEmpty() ? myMainPanel : myPanelWithSelectedFiles) {
|
||||
@Override
|
||||
public JComponent getPreferredFocusedSimpleComponent() {
|
||||
return getPreferredFocusComponent();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JComponent getPreferredFocusComponent() {
|
||||
return myFileNameField;
|
||||
return !myIncludeBaseRevisionTextCheckBox.isVisible() || myChanges.isEmpty() ? myMainPanel : myPanelWithSelectedFiles;
|
||||
}
|
||||
|
||||
public void installOkEnabledListener(final Consumer<Boolean> runnable) {
|
||||
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.openapi.vcs.changes.ui;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
public class ComplexFocusedComponentWrapper extends JPanel {
|
||||
|
||||
public ComplexFocusedComponentWrapper(@NotNull JComponent component) {
|
||||
super(new BorderLayout());
|
||||
add(component);
|
||||
}
|
||||
|
||||
public JComponent getPreferredFocusedSimpleComponent() {
|
||||
//return all panel by default
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.CommitSession;
|
||||
import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy;
|
||||
import com.intellij.util.Alarm;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -68,8 +69,7 @@ public class SessionDialog extends DialogWrapper {
|
||||
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myConfigurationComponent instanceof ComplexFocusedComponentWrapper ?
|
||||
((ComplexFocusedComponentWrapper)myConfigurationComponent).getPreferredFocusedSimpleComponent() : myConfigurationComponent;
|
||||
return IdeFocusTraversalPolicy.getPreferredFocusedComponent(myConfigurationComponent);
|
||||
}
|
||||
|
||||
private void updateButtons() {
|
||||
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
package com.intellij.openapi.vcs.changes.committed;
|
||||
|
||||
import com.intellij.ide.startup.impl.StartupManagerImpl;
|
||||
import com.intellij.openapi.components.ProjectComponent;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
|
||||
import com.intellij.testFramework.fixtures.TempDirTestFixture;
|
||||
import com.intellij.testFramework.vcs.AbstractJunitVcsTestCase;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
*/
|
||||
public class ExternalChangesDetectionVcsTest extends AbstractJunitVcsTestCase {
|
||||
private MockAbstractVcs myVcs;
|
||||
private ProjectLevelVcsManagerImpl myVcsManager;
|
||||
private LocalFileSystem myLFS;
|
||||
private ChangeListManager myChangeListManager;
|
||||
private VcsDirtyScopeManager myVcsDirtyScopeManager;
|
||||
private TempDirTestFixture myTempDirTestFixture;
|
||||
private File myClientRoot;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory();
|
||||
myTempDirTestFixture = fixtureFactory.createTempDirTestFixture();
|
||||
myTempDirTestFixture.setUp();
|
||||
|
||||
myClientRoot = new File(myTempDirTestFixture.getTempDirPath(), "clientroot");
|
||||
myClientRoot.mkdir();
|
||||
|
||||
initProject(myClientRoot, ExternalChangesDetectionVcsTest.this.getTestName());
|
||||
|
||||
((StartupManagerImpl)StartupManager.getInstance(myProject)).runPostStartupActivities();
|
||||
|
||||
myVcs = new MockAbstractVcs(myProject);
|
||||
myVcs.setChangeProvider(new MyMockChangeProvider());
|
||||
myVcsManager = (ProjectLevelVcsManagerImpl)ProjectLevelVcsManager.getInstance(myProject);
|
||||
myVcsManager.registerVcs(myVcs);
|
||||
myVcsManager.setDirectoryMapping("", myVcs.getName());
|
||||
|
||||
myLFS = LocalFileSystem.getInstance();
|
||||
myChangeListManager = ChangeListManager.getInstance(myProject);
|
||||
((ProjectComponent)myChangeListManager).projectOpened();
|
||||
myVcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(myProject);
|
||||
((ProjectComponent)myVcsDirtyScopeManager).projectOpened();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
myVcsManager.unregisterVcs(myVcs);
|
||||
((ProjectComponent)myChangeListManager).projectClosed();
|
||||
((ProjectComponent)myVcsDirtyScopeManager).projectClosed();
|
||||
|
||||
tearDownProject();
|
||||
if (myTempDirTestFixture != null) {
|
||||
myTempDirTestFixture.tearDown();
|
||||
myTempDirTestFixture = null;
|
||||
}
|
||||
FileUtil.delete(myClientRoot);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletion() throws Exception {
|
||||
final File f = new File(myClientRoot, "f.txt");
|
||||
f.createNewFile();
|
||||
final VirtualFile vf = myLFS.refreshAndFindFileByIoFile(f);
|
||||
myChangeListManager.ensureUpToDate(false);
|
||||
((ChangeListManagerImpl) myChangeListManager).getUnversionedFiles().contains(vf);
|
||||
FileUtil.delete(f);
|
||||
myWorkingCopyDir.refresh(false, true);
|
||||
myChangeListManager.ensureUpToDate(false);
|
||||
((ChangeListManagerImpl) myChangeListManager).getUnversionedFiles().isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeneration() throws Exception {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
final File f = new File(myClientRoot, "f" + i + ".txt");
|
||||
f.createNewFile();
|
||||
}
|
||||
myWorkingCopyDir.refresh(false, true);
|
||||
myChangeListManager.ensureUpToDate(false);
|
||||
final List<VirtualFile> unversionedFiles = ((ChangeListManagerImpl)myChangeListManager).getUnversionedFiles();
|
||||
final Pattern pattern = Pattern.compile("f([0-9])+\\.txt");
|
||||
int cnt = 0;
|
||||
for (VirtualFile unversionedFile : unversionedFiles) {
|
||||
if (VfsUtil.isAncestor(myWorkingCopyDir, unversionedFile, true)) {
|
||||
++ cnt;
|
||||
Assert.assertTrue(pattern.matcher(unversionedFile.getName()).matches());
|
||||
}
|
||||
}
|
||||
Assert.assertEquals(100, cnt);
|
||||
}
|
||||
|
||||
/*@Test
|
||||
public void testMoveDir() throws Exception {
|
||||
final File root = new File(myClientRoot, "was");
|
||||
root.mkdir();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
final File dir = new File(root, "dir" + i);
|
||||
dir.mkdir();
|
||||
for (int j = 0; j < 10; j++) {
|
||||
final File f = new File(dir, "f" + j + ".txt");
|
||||
f.createNewFile();
|
||||
}
|
||||
}
|
||||
myWorkingCopyDir.refresh(false, true);
|
||||
myChangeListManager.ensureUpToDate(false);
|
||||
List<VirtualFile> unversionedFiles = ((ChangeListManagerImpl)myChangeListManager).getUnversionedFiles();
|
||||
final Pattern pattern = Pattern.compile("f([0-9])+\\.txt");
|
||||
final Pattern patternDir = Pattern.compile("dir([0-9])+");
|
||||
int cnt = 0;
|
||||
for (VirtualFile unversionedFile : unversionedFiles) {
|
||||
if (VfsUtil.isAncestor(myWorkingCopyDir, unversionedFile, true) && (! "was".equals(unversionedFile.getName()))) {
|
||||
++ cnt;
|
||||
Assert.assertTrue(pattern.matcher(unversionedFile.getName()).matches() || patternDir.matcher(unversionedFile.getName()).matches());
|
||||
}
|
||||
}
|
||||
Assert.assertEquals(110, cnt);
|
||||
final File renamedFile = new File(myClientRoot, "newName");
|
||||
FileUtil.copyDir(root, renamedFile);
|
||||
FileUtil.delete(root);
|
||||
|
||||
myWorkingCopyDir.refresh(false, true);
|
||||
myChangeListManager.ensureUpToDate(false);
|
||||
unversionedFiles = ((ChangeListManagerImpl)myChangeListManager).getUnversionedFiles();
|
||||
|
||||
cnt = 0;
|
||||
for (VirtualFile unversionedFile : unversionedFiles) {
|
||||
if (VfsUtil.isAncestor(myWorkingCopyDir, unversionedFile, true) && (! "newName".equals(unversionedFile.getName()))) {
|
||||
++ cnt;
|
||||
Assert.assertTrue((pattern.matcher(unversionedFile.getName()).matches() || patternDir.matcher(unversionedFile.getName()).matches()));
|
||||
if (unversionedFile.getPath().indexOf("newName") == -1) {
|
||||
System.out.println("wrong " + unversionedFile.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
Assert.assertEquals(110, cnt);
|
||||
}*/
|
||||
|
||||
private static class MyMockChangeProvider implements ChangeProvider {
|
||||
@Override
|
||||
public void doCleanup(List<VirtualFile> files) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getChanges(VcsDirtyScope dirtyScope,
|
||||
final ChangelistBuilder builder,
|
||||
ProgressIndicator progress,
|
||||
ChangeListManagerGate addGate) throws VcsException {
|
||||
for (FilePath path : dirtyScope.getDirtyFiles()) {
|
||||
builder.processUnversionedFile(path.getVirtualFile());
|
||||
}
|
||||
final Processor<VirtualFile> processor = new Processor<VirtualFile>() {
|
||||
@Override
|
||||
public boolean process(final VirtualFile vf) {
|
||||
builder.processUnversionedFile(vf);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
for (FilePath dir : dirtyScope.getRecursivelyDirtyDirectories()) {
|
||||
VfsUtil.processFilesRecursively(dir.getVirtualFile(), processor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModifiedDocumentTrackingRequired() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+355
@@ -0,0 +1,355 @@
|
||||
package com.intellij.openapi.vcs.changes.committed;
|
||||
|
||||
import com.intellij.ide.startup.impl.StartupManagerImpl;
|
||||
import com.intellij.openapi.components.ProjectComponent;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vcs.*;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ChangeList;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.checkin.CheckinEnvironment;
|
||||
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
|
||||
import com.intellij.openapi.vcs.rollback.RollbackEnvironment;
|
||||
import com.intellij.openapi.vcs.rollback.RollbackProgressListener;
|
||||
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
|
||||
import com.intellij.openapi.vcs.update.SequentialUpdatesContext;
|
||||
import com.intellij.openapi.vcs.update.UpdateEnvironment;
|
||||
import com.intellij.openapi.vcs.update.UpdateSession;
|
||||
import com.intellij.openapi.vcs.update.UpdatedFiles;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.testFramework.UsefulTestCase;
|
||||
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
|
||||
import com.intellij.testFramework.fixtures.TempDirTestFixture;
|
||||
import com.intellij.testFramework.vcs.AbstractJunitVcsTestCase;
|
||||
import com.intellij.util.NullableFunction;
|
||||
import com.intellij.util.PairConsumer;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import junit.framework.Assert;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 12/21/10
|
||||
* Time: 2:03 PM
|
||||
*/
|
||||
public class VcsEventsListenerTest extends AbstractJunitVcsTestCase {
|
||||
private AbstractVcs myVcs;
|
||||
private ProjectLevelVcsManagerImpl myVcsManager;
|
||||
private ChangeListManager myChangeListManager;
|
||||
private TempDirTestFixture myTempDirFixture;
|
||||
private File myClientRoot;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory();
|
||||
myTempDirFixture = fixtureFactory.createTempDirTestFixture();
|
||||
myTempDirFixture.setUp();
|
||||
|
||||
myClientRoot = new File(myTempDirFixture.getTempDirPath(), "clientroot");
|
||||
myClientRoot.mkdir();
|
||||
|
||||
initProject(myClientRoot, VcsEventsListenerTest.this.getTestName());
|
||||
|
||||
((StartupManagerImpl)StartupManager.getInstance(myProject)).runPostStartupActivities();
|
||||
|
||||
myChangeListManager = ChangeListManager.getInstance(myProject);
|
||||
myVcs = VcsActiveEnvironmentsProxy.proxyVcs(new MyVcs(myProject, "mock"));
|
||||
myVcsManager = (ProjectLevelVcsManagerImpl)ProjectLevelVcsManager.getInstance(myProject);
|
||||
myVcsManager.registerVcs(myVcs);
|
||||
myVcsManager.setDirectoryMapping(myWorkingCopyDir.getPath(), myVcs.getName());
|
||||
|
||||
((ProjectComponent)myChangeListManager).projectOpened();
|
||||
}
|
||||
catch (Exception e) {
|
||||
tearDown();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (myVcsManager != null && myVcs != null) {
|
||||
myVcsManager.unregisterVcs(myVcs);
|
||||
}
|
||||
|
||||
((ProjectComponent)myChangeListManager).projectClosed();
|
||||
tearDownProject();
|
||||
if (myTempDirFixture != null) {
|
||||
myTempDirFixture.tearDown();
|
||||
myTempDirFixture = null;
|
||||
}
|
||||
FileUtil.delete(myClientRoot);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
UsefulTestCase.clearFields(this);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
//noinspection ThrowFromFinallyBlock
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleListeningWithProxy() throws Exception {
|
||||
final VcsEventsListenerManager manager = myVcsManager.getVcsEventsListenerManager();
|
||||
final List<VirtualFile> list = Arrays.asList(new VirtualFile[]{myWorkingCopyDir});
|
||||
final MyCheckinListener listener = new MyCheckinListener(list);
|
||||
final Object key = manager.addCheckin(new ForwardingListener<CheckinEnvironment>(listener));
|
||||
|
||||
myVcs.getCheckinEnvironment().scheduleUnversionedFilesForAddition(list);
|
||||
|
||||
Assert.assertTrue(listener.isChecked());
|
||||
listener.assertCheckOk();
|
||||
|
||||
listener.reset();
|
||||
|
||||
manager.removeCheckin(key);
|
||||
listener.reset();
|
||||
myVcs.getCheckinEnvironment().scheduleUnversionedFilesForAddition(list);
|
||||
Assert.assertFalse(listener.isChecked());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleListeningWithoutProxy() throws Exception {
|
||||
myVcsManager.setDirectoryMapping(myWorkingCopyDir.getPath(), "svn");
|
||||
|
||||
testSimpleListeningWithProxy();
|
||||
}
|
||||
|
||||
private static class MyVcs extends MockAbstractVcs {
|
||||
private MyVcs(Project project, String name) {
|
||||
super(project, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UpdateEnvironment createUpdateEnvironment() {
|
||||
return new UpdateEnvironment() {
|
||||
@Override
|
||||
public void fillGroups(UpdatedFiles updatedFiles) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public UpdateSession updateDirectories(@NotNull FilePath[] contentRoots,
|
||||
UpdatedFiles updatedFiles,
|
||||
ProgressIndicator progressIndicator,
|
||||
@NotNull Ref<SequentialUpdatesContext> context) throws ProcessCanceledException {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configurable createConfigurable(Collection<FilePath> files) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateOptions(Collection<FilePath> roots) {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RollbackEnvironment createRollbackEnvironment() {
|
||||
return new RollbackEnvironment() {
|
||||
@Override
|
||||
public String getRollbackOperationName() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollbackChanges(List<Change> changes,
|
||||
List<VcsException> vcsExceptions,
|
||||
@NotNull RollbackProgressListener listener) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollbackMissingFileDeletion(List<FilePath> files,
|
||||
List<VcsException> exceptions,
|
||||
RollbackProgressListener listener) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollbackModifiedWithoutCheckout(List<VirtualFile> files,
|
||||
List<VcsException> exceptions,
|
||||
RollbackProgressListener listener) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollbackIfUnchanged(VirtualFile file) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CheckinEnvironment createCheckinEnvironment() {
|
||||
return new CheckinEnvironment() {
|
||||
@Override
|
||||
public RefreshableOnComponent createAdditionalOptionsPanel(CheckinProjectPanel panel,
|
||||
PairConsumer<Object, Object> additionalDataConsumer) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultMessageFor(FilePath[] filesToCheckin) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpId() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCheckinOperationName() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VcsException> commit(List<Change> changes, String preparedComment) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VcsException> commit(List<Change> changes,
|
||||
String preparedComment,
|
||||
@NotNull NullableFunction<Object, Object> parametersHolder, Set<String> feedback) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VcsException> scheduleMissingFileForDeletion(List<FilePath> files) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VcsException> scheduleUnversionedFilesForAddition(List<VirtualFile> files) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keepChangeListAfterCommit(ChangeList changeList) {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshAfterCommitNeeded() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyCheckinListener implements CheckinEnvironment {
|
||||
private boolean myChecked;
|
||||
private boolean myAssertOk;
|
||||
private final List<VirtualFile> myCheckList;
|
||||
|
||||
public MyCheckinListener(final List<VirtualFile> checkList) {
|
||||
myCheckList = checkList;
|
||||
myChecked = false;
|
||||
myAssertOk = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefreshableOnComponent createAdditionalOptionsPanel(CheckinProjectPanel panel,
|
||||
PairConsumer<Object, Object> additionalDataConsumer) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getDefaultMessageFor(FilePath[] filesToCheckin) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getHelpId() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getCheckinOperationName() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public List<VcsException> commit(List<Change> changes, String preparedComment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VcsException> commit(List<Change> changes,
|
||||
String preparedComment,
|
||||
@NotNull NullableFunction<Object, Object> parametersHolder, Set<String> feedback) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VcsException> scheduleMissingFileForDeletion(List<FilePath> files) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VcsException> scheduleUnversionedFilesForAddition(List<VirtualFile> files) {
|
||||
myChecked = true;
|
||||
myAssertOk = myCheckList.equals(files);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keepChangeListAfterCommit(ChangeList changeList) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshAfterCommitNeeded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return myChecked;
|
||||
}
|
||||
|
||||
public void assertCheckOk() {
|
||||
Assert.assertTrue(myAssertOk);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
myAssertOk = true;
|
||||
myChecked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,10 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
import com.intellij.vcs.log.*;
|
||||
import com.intellij.vcs.log.Hash;
|
||||
import com.intellij.vcs.log.VcsFullCommitDetails;
|
||||
import com.intellij.vcs.log.VcsRef;
|
||||
import com.intellij.vcs.log.VcsShortCommitDetails;
|
||||
import com.intellij.vcs.log.data.LoadingDetails;
|
||||
import com.intellij.vcs.log.data.VcsLogDataHolder;
|
||||
import com.intellij.vcs.log.data.VisiblePack;
|
||||
@@ -157,6 +160,7 @@ public class GraphTableModel extends AbstractTableModel {
|
||||
|
||||
/**
|
||||
* Requests the proper data provider to load more data from the log & recreate the model.
|
||||
*
|
||||
* @param onLoaded will be called upon task completion on the EDT.
|
||||
*/
|
||||
public void requestToLoadMore(@NotNull Runnable onLoaded) {
|
||||
@@ -183,7 +187,9 @@ public class GraphTableModel extends AbstractTableModel {
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
return data.getAuthor().getName() + (data.getAuthor().equals(data.getCommitter()) ? "" : "*");
|
||||
String authorString = data.getAuthor().getName();
|
||||
if (authorString.isEmpty()) authorString = data.getAuthor().getEmail();
|
||||
return authorString + (data.getAuthor().equals(data.getCommitter()) ? "" : "*");
|
||||
}
|
||||
case DATE_COLUMN:
|
||||
if (data == null || data.getAuthorTime() < 0) {
|
||||
@@ -208,6 +214,7 @@ public class GraphTableModel extends AbstractTableModel {
|
||||
* Returns Changes for commits at selected rows.<br/>
|
||||
* Rows are given in the order as they appear in the table, i. e. in reverse chronological order. <br/>
|
||||
* Changes can be returned as-is, i.e. with duplicate changes for a single file.
|
||||
*
|
||||
* @return Changes selected in all rows, or null if this data is not ready yet.
|
||||
*/
|
||||
@Nullable
|
||||
|
||||
@@ -302,10 +302,14 @@ public class XDebugSessionImpl implements XDebugSession {
|
||||
disableSlaveBreakpoints(dependentBreakpointManager);
|
||||
processAllBreakpoints(true, false);
|
||||
|
||||
myBreakpointListener = new MyBreakpointListener();
|
||||
breakpointManager.addBreakpointListener(myBreakpointListener);
|
||||
myDependentBreakpointListener = new MyDependentBreakpointListener();
|
||||
dependentBreakpointManager.addListener(myDependentBreakpointListener);
|
||||
if (myBreakpointListener == null) {
|
||||
myBreakpointListener = new MyBreakpointListener();
|
||||
breakpointManager.addBreakpointListener(myBreakpointListener);
|
||||
}
|
||||
if (myDependentBreakpointListener == null) {
|
||||
myDependentBreakpointListener = new MyDependentBreakpointListener();
|
||||
dependentBreakpointManager.addListener(myDependentBreakpointListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package git4idea.actions;
|
||||
|
||||
import com.intellij.dvcs.repo.Repository;
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
@@ -114,19 +115,18 @@ public abstract class GitRepositoryAction extends DumbAwareAction {
|
||||
if (files != null) {
|
||||
for (VirtualFile file : files) {
|
||||
GitRepositoryManager manager = GitUtil.getRepositoryManager(project);
|
||||
if (manager == null) {
|
||||
return false;
|
||||
}
|
||||
final GitRepository repositoryForFile = manager.getRepositoryForFile(file);
|
||||
if (repositoryForFile != null && repositoryForFile.getState() == GitRepository.State.REBASING) {
|
||||
return true;
|
||||
}
|
||||
if (isRebasing(manager.getRepositoryForFile(file))) return true;
|
||||
}
|
||||
}
|
||||
if (isRebasing(GitBranchUtil.getCurrentRepository(project))) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isRebasing(@Nullable GitRepository repository) {
|
||||
return repository != null && repository.getState() == Repository.State.REBASING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get git roots for the project. The method shows dialogs in the case when roots cannot be retrieved, so it should be called
|
||||
* from the event dispatch thread.
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package git4idea.repo;
|
||||
|
||||
import com.intellij.dvcs.DvcsUtil;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -298,7 +299,7 @@ public class GitUntrackedFilesHolder implements Disposable, BulkFileListener {
|
||||
private boolean belongsToThisRepository(VirtualFile file) {
|
||||
// this check should be quick
|
||||
// we shouldn't create a full instance repository here because it may lead to SOE while many unversioned files will be processed
|
||||
final GitRepository repository = myRepositoryManager.getRepositoryForFile(file, false);
|
||||
final GitRepository repository = myRepositoryManager.getRepositoryForRootQuick(DvcsUtil.getVcsRoot(myProject, file));
|
||||
return repository != null && repository.getRoot().equals(myRoot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,4 +130,23 @@ public class JUnitRerunFailedTestsTest extends LightCodeInsightFixtureTestCase
|
||||
});
|
||||
assertNull(TestMethods.getTestPresentation(testProxy, project, searchScope));
|
||||
}
|
||||
|
||||
public void testInnerClass() throws Exception {
|
||||
myFixture.addClass("public class TestClass {\n" +
|
||||
" public static class Tests extends junit.framework.TestCase {\n" +
|
||||
" public void testFoo() throws Exception {}\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
final SMTestProxy testProxy = new SMTestProxy("testFoo", false, "java:test://TestClass$Tests.testFoo");
|
||||
final Project project = getProject();
|
||||
final GlobalSearchScope searchScope = GlobalSearchScope.projectScope(project);
|
||||
testProxy.setLocator(JavaTestLocator.INSTANCE);
|
||||
Location location = testProxy.getLocation(project, searchScope);
|
||||
assertNotNull(location);
|
||||
PsiElement element = location.getPsiElement();
|
||||
assertTrue(element instanceof PsiMethod);
|
||||
String name = ((PsiMethod)element).getName();
|
||||
assertEquals(name, "testFoo");
|
||||
}
|
||||
}
|
||||
|
||||
+50
-26
@@ -65,26 +65,25 @@ public class JUnitTreeByDescriptionHierarchyTest {
|
||||
|
||||
"##teamcity[enteredTheMatrix]\n" +
|
||||
"##teamcity[rootName name = 'root' location = 'java:suite://root']\n" +
|
||||
"##teamcity[testSuiteFinished name='root']\n" +
|
||||
"##teamcity[testSuiteStarted name ='TestA']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name='TestA']\n" +
|
||||
"##teamcity[testSuiteStarted name='|[0|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[0|]' locationHint='java:test://a.TestA.testName|[0|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[0|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[1|]']\n" +
|
||||
"##teamcity[testSuiteStarted name='|[1|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[1|]' locationHint='java:test://a.TestA.testName|[1|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='TestA']\n" +
|
||||
"##teamcity[testSuiteStarted name ='TestB']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name='TestB']\n" +
|
||||
"##teamcity[testSuiteStarted name='|[0|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[0|]' locationHint='java:test://a.TestB.testName|[0|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[0|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[1|]']\n" +
|
||||
"##teamcity[testSuiteStarted name='|[1|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[1|]' locationHint='java:test://a.TestB.testName|[1|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[1|]']\n" +
|
||||
@@ -109,17 +108,16 @@ public class JUnitTreeByDescriptionHierarchyTest {
|
||||
//start
|
||||
"##teamcity[enteredTheMatrix]\n" +
|
||||
"##teamcity[rootName name = 'TestA' comment = 'a' location = 'java:suite://a.TestA']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name='|[0|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[0|]' locationHint='java:test://a.TestA.testName|[0|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[0|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[1|]']\n" +
|
||||
"##teamcity[testSuiteStarted name='|[1|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[1|]' locationHint='java:test://a.TestA.testName|[1|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='TestA']\n");
|
||||
"##teamcity[testSuiteFinished name='|[1|]']\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -154,16 +152,15 @@ public class JUnitTreeByDescriptionHierarchyTest {
|
||||
//started
|
||||
"##teamcity[enteredTheMatrix]\n" +
|
||||
"##teamcity[rootName name = 'root' location = 'java:suite://root']\n" +
|
||||
"##teamcity[testSuiteFinished name='root']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ASuite1']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ATest']\n" +
|
||||
"##teamcity[testSuiteStarted name='ASuite1']\n" +
|
||||
"##teamcity[testSuiteStarted name='ATest']\n" +
|
||||
"##teamcity[testStarted name='test1' locationHint='java:test://ATest.test1']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='test1']\n" +
|
||||
"##teamcity[testSuiteFinished name='ATest']\n" +
|
||||
"##teamcity[testSuiteFinished name='ASuite1']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ASuite2']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ATest']\n" +
|
||||
"##teamcity[testSuiteStarted name='ASuite2']\n" +
|
||||
"##teamcity[testSuiteStarted name='ATest']\n" +
|
||||
"##teamcity[testStarted name='test1' locationHint='java:test://ATest.test1']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='test1']\n" +
|
||||
@@ -204,8 +201,37 @@ public class JUnitTreeByDescriptionHierarchyTest {
|
||||
"##teamcity[rootName name = 'TestA' location = 'java:suite://TestA']\n" +
|
||||
"##teamcity[testStarted name='testName' locationHint='java:test://TestA.testName']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName']\n" +
|
||||
"##teamcity[testSuiteFinished name='TestA']\n");
|
||||
"##teamcity[testFinished name='testName']\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameterizedTestsUpsideDown() throws Exception {
|
||||
final Description aTestClass = Description.createSuiteDescription("ATest");
|
||||
final ArrayList<Description> tests = new ArrayList<Description>();
|
||||
final Description testMethod = Description.createSuiteDescription("testName");
|
||||
aTestClass.addChild(testMethod);
|
||||
for (String paramName : new String[]{"[0]", "[1]"}) {
|
||||
final Description testDescription = Description.createTestDescription("ATest", "testName" + paramName);
|
||||
tests.add(testDescription);
|
||||
testMethod.addChild(testDescription);
|
||||
}
|
||||
doTest(aTestClass, tests,
|
||||
"##teamcity[suiteTreeStarted name='testName' locationHint='java:suite://testName']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[0|]' locationHint='java:test://ATest.testName|[0|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[1|]' locationHint='java:test://ATest.testName|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='testName']\n",
|
||||
|
||||
|
||||
"##teamcity[enteredTheMatrix]\n" +
|
||||
"##teamcity[rootName name = 'ATest' location = 'java:suite://ATest']\n" +
|
||||
"##teamcity[testSuiteStarted name='testName']\n" +
|
||||
"##teamcity[testStarted name='testName|[0|]' locationHint='java:test://ATest.testName|[0|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[0|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[1|]' locationHint='java:test://ATest.testName|[1|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='testName']\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -240,21 +266,20 @@ public class JUnitTreeByDescriptionHierarchyTest {
|
||||
//start
|
||||
"##teamcity[enteredTheMatrix]\n" +
|
||||
"##teamcity[rootName name = 'root' location = 'java:suite://root']\n" +
|
||||
"##teamcity[testSuiteFinished name='root']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ATest']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name='ATest']\n" +
|
||||
"##teamcity[testSuiteStarted name='|[0|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[0|]' locationHint='java:test://ATest.testName|[0|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[0|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[1|]']\n" +
|
||||
"##teamcity[testSuiteStarted name='|[1|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[1|]' locationHint='java:test://ATest.testName|[1|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='ATest']\n" +
|
||||
"##teamcity[testSuiteStarted name ='suite']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ATest']\n" +
|
||||
"##teamcity[testSuiteStarted name='suite']\n" +
|
||||
"##teamcity[testSuiteStarted name='ATest']\n" +
|
||||
"##teamcity[testStarted name='test' locationHint='java:test://ATest.test']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='test']\n" +
|
||||
@@ -298,7 +323,6 @@ public class JUnitTreeByDescriptionHierarchyTest {
|
||||
"##teamcity[rootName name = 'TestA' location = 'java:suite://TestA']\n" +
|
||||
"##teamcity[testStarted name='warning' locationHint='java:test://junit.framework.TestSuite$1.warning']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='warning']\n" +
|
||||
"##teamcity[testSuiteFinished name='TestA']\n");
|
||||
"##teamcity[testFinished name='warning']\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ import org.junit.runner.notification.Failure;
|
||||
import org.junit.runner.notification.RunListener;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.*;
|
||||
|
||||
public class SMTestSender extends RunListener {
|
||||
@@ -41,16 +43,14 @@ public class SMTestSender extends RunListener {
|
||||
public static final String EMPTY_SUITE_NAME = "junit.framework.TestSuite$1";
|
||||
public static final String EMPTY_SUITE_WARNING = "warning";
|
||||
|
||||
private String myCurrentSuiteName;
|
||||
private String myCurrentClassName;
|
||||
private String myParamName;
|
||||
private List myStartedSuites = new ArrayList();
|
||||
private Map myParents = new HashMap();
|
||||
private final PrintStream myPrintStream;
|
||||
private String myRootName;
|
||||
|
||||
private PrintStream myPrintStream = System.out;
|
||||
private final Map myParents = new HashMap();
|
||||
private final Map mySuites = new HashMap();
|
||||
|
||||
|
||||
public SMTestSender() {}
|
||||
public SMTestSender() {
|
||||
myPrintStream = System.out;
|
||||
}
|
||||
|
||||
public SMTestSender(PrintStream printStream) {
|
||||
myPrintStream = printStream;
|
||||
@@ -62,112 +62,90 @@ public class SMTestSender extends RunListener {
|
||||
|
||||
public void testRunStarted(Description description) throws Exception {
|
||||
myPrintStream.println("##teamcity[enteredTheMatrix]");
|
||||
if (myCurrentClassName != null && !myCurrentClassName.startsWith("[")) {
|
||||
int lastPointIdx = myCurrentClassName.lastIndexOf('.');
|
||||
String name = myCurrentClassName;
|
||||
if (myRootName != null && !myRootName.startsWith("[")) {
|
||||
int lastPointIdx = myRootName.lastIndexOf('.');
|
||||
String name = myRootName;
|
||||
String comment = null;
|
||||
if (lastPointIdx >= 0) {
|
||||
name = myCurrentClassName.substring(lastPointIdx + 1);
|
||||
comment = myCurrentClassName.substring(0, lastPointIdx);
|
||||
name = myRootName.substring(lastPointIdx + 1);
|
||||
comment = myRootName.substring(0, lastPointIdx);
|
||||
}
|
||||
|
||||
myPrintStream.println("##teamcity[rootName name = \'" + escapeName(name) +
|
||||
(comment != null ? ("\' comment = \'" + escapeName(comment)) : "") + "\'" +
|
||||
" location = \'java:suite://" + escapeName(myCurrentClassName) +
|
||||
" location = \'java:suite://" + escapeName(myRootName) +
|
||||
"\']");
|
||||
myCurrentClassName = getShortName(myCurrentClassName);
|
||||
myRootName = getShortName(myRootName);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRunFinished(Result result) throws Exception {
|
||||
if (myParamName != null) {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(myParamName) + "\']");
|
||||
}
|
||||
if (myCurrentClassName != null) {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(myCurrentClassName) + "\']");
|
||||
}
|
||||
if (myCurrentSuiteName != null) {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(getShortName(myCurrentSuiteName)) + "\']");
|
||||
for (int i = myStartedSuites.size() - 1; i>= 0; i--) {
|
||||
Object parent = myStartedSuites.get(i);
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName((String)parent) + "\']");
|
||||
}
|
||||
myStartedSuites.clear();
|
||||
}
|
||||
|
||||
public void testStarted(Description description) throws Exception {
|
||||
final String methodName = JUnit4ReflectionUtil.getMethodName(description);
|
||||
final String classFQN = JUnit4ReflectionUtil.getClassName(description);
|
||||
final int paramStart = methodName.indexOf('[');
|
||||
if (myParamName != null){
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(myParamName) + "\']");
|
||||
myParamName = null;
|
||||
}
|
||||
|
||||
final List suites = (List)myParents.get(description);
|
||||
if (suites != null && !suites.isEmpty()) {
|
||||
String currentSuite = (String)suites.get(0);
|
||||
List descriptors = (List)mySuites.get(currentSuite);
|
||||
final List parents = (List)myParents.get(description);
|
||||
if (parents != null) {
|
||||
|
||||
if (descriptors.isEmpty()) {
|
||||
currentSuite = (String)suites.get(1);
|
||||
descriptors = (List)mySuites.get(currentSuite);
|
||||
List parentsHierarchy = (List)parents.remove(0);
|
||||
|
||||
int idx = 0;
|
||||
String currentClass;
|
||||
String currentParent;
|
||||
while (idx < myStartedSuites.size() && idx < parentsHierarchy.size()) {
|
||||
currentClass = (String)myStartedSuites.get(idx);
|
||||
currentParent = getShortName(JUnit4ReflectionUtil.getClassName((Description)parentsHierarchy.get(parentsHierarchy.size() - 1 - idx)));
|
||||
if (!currentClass.equals(currentParent)) break;
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (!currentSuite.equals(myCurrentSuiteName)) {
|
||||
finishCurrentSuite();
|
||||
myCurrentSuiteName = currentSuite;
|
||||
myPrintStream.println("##teamcity[testSuiteStarted name =\'" + escapeName(getShortName(myCurrentSuiteName)) + "\']");
|
||||
for (int i = myStartedSuites.size() - 1; i >= idx; i--) {
|
||||
currentClass = (String)myStartedSuites.remove(i);
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(currentClass) + "\']");
|
||||
}
|
||||
|
||||
descriptors.remove(description);
|
||||
}
|
||||
else if (myCurrentSuiteName != null){
|
||||
finishCurrentSuite();
|
||||
myCurrentSuiteName = null;
|
||||
}
|
||||
|
||||
String className = getShortName(classFQN);
|
||||
if (!myEmptyTests.isEmpty() && isWarning(methodName, classFQN)) {
|
||||
className = (String)myEmptyTests.remove(0);
|
||||
}
|
||||
|
||||
if (!className.equals(myCurrentClassName)) {
|
||||
if (myCurrentClassName != null) {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(myCurrentClassName) + "\']");
|
||||
}
|
||||
myCurrentClassName = className;
|
||||
myPrintStream.println("##teamcity[testSuiteStarted name =\'" + escapeName(myCurrentClassName) + "\']");
|
||||
}
|
||||
if (paramStart > -1) {
|
||||
final String paramName = methodName.substring(paramStart, methodName.length());
|
||||
if (!paramName.equals(myParamName)) {
|
||||
myParamName = paramName;
|
||||
myPrintStream.println("##teamcity[testSuiteStarted name =\'" + escapeName(myParamName) + "\']");
|
||||
for (int i = idx; i < parentsHierarchy.size(); i++) {
|
||||
Description parent = (Description)parentsHierarchy.get(parentsHierarchy.size() - 1 - i);
|
||||
final String className = getShortName(JUnit4ReflectionUtil.getClassName(parent));
|
||||
if (!className.equals(myRootName)) {
|
||||
myPrintStream.println("##teamcity[testSuiteStarted name=\'" + escapeName(className) + "\']");
|
||||
myStartedSuites.add(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myPrintStream.println("##teamcity[testStarted name=\'" + escapeName(methodName) + "\' " +
|
||||
getTestMethodLocation(methodName, classFQN) + "]");
|
||||
}
|
||||
|
||||
private void finishCurrentSuite() {
|
||||
if (myCurrentClassName != null) {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(myCurrentClassName) + "\']");
|
||||
myCurrentClassName = null;
|
||||
}
|
||||
if (myCurrentSuiteName != null) {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(getShortName(myCurrentSuiteName)) + "\']");
|
||||
}
|
||||
}
|
||||
|
||||
public void testFinished(Description description) throws Exception {
|
||||
myPrintStream.println("\n##teamcity[testFinished name=\'" + escapeName(JUnit4ReflectionUtil.getMethodName(description)) + "\']");
|
||||
}
|
||||
|
||||
public void testFailure(Failure failure) throws Exception {
|
||||
final String failureMessage = failure.getMessage();
|
||||
final String trace = failure.getTrace();
|
||||
final Map attrs = new HashMap();
|
||||
attrs.put("name", JUnit4ReflectionUtil.getMethodName(failure.getDescription()));
|
||||
final ComparisonFailureData notification = createExceptionNotification(failure.getException());
|
||||
ComparisonFailureData.registerSMAttributes(notification, trace, failureMessage, attrs);
|
||||
myPrintStream.println(ServiceMessage.asString(ServiceMessageTypes.TEST_FAILED, attrs));
|
||||
try {
|
||||
final String trace = failure.getTrace();
|
||||
final ComparisonFailureData notification = createExceptionNotification(failure.getException());
|
||||
ComparisonFailureData.registerSMAttributes(notification, trace, failure.getMessage(), attrs);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
final StringWriter stringWriter = new StringWriter();
|
||||
final PrintWriter writer = new PrintWriter(stringWriter);
|
||||
e.printStackTrace(writer);
|
||||
ComparisonFailureData.registerSMAttributes(null, stringWriter.toString(), e.getMessage(), attrs);
|
||||
}
|
||||
finally {
|
||||
myPrintStream.println(ServiceMessage.asString(ServiceMessageTypes.TEST_FAILED, attrs));
|
||||
}
|
||||
}
|
||||
|
||||
public void testAssumptionFailure(Failure failure) {
|
||||
@@ -249,39 +227,29 @@ public class SMTestSender extends RunListener {
|
||||
return messageLength < threshold;
|
||||
}
|
||||
|
||||
private final List myEmptyTests = new ArrayList();
|
||||
|
||||
private void sendTree(Description description, Description parent, Description suiteParent) {
|
||||
private void sendTree(Description description, Description parent, List currentParents) {
|
||||
List pParents = new ArrayList(3);
|
||||
pParents.addAll(currentParents);
|
||||
if (parent != null && !myRootName.equals(JUnit4ReflectionUtil.getClassName(parent))) {
|
||||
pParents.add(0, parent);
|
||||
}
|
||||
|
||||
String className = JUnit4ReflectionUtil.getClassName(description);
|
||||
if (description.getChildren().isEmpty()) {
|
||||
final String methodName = JUnit4ReflectionUtil.getMethodName((Description)description);
|
||||
if (methodName != null) {
|
||||
if (isWarning(methodName, className)) {
|
||||
className = JUnit4ReflectionUtil.getClassName(parent);
|
||||
myEmptyTests.add(getShortName(className));
|
||||
}
|
||||
myPrintStream.println("##teamcity[suiteTreeNode name=\'" + escapeName(methodName) + "\' " + getTestMethodLocation(methodName, className) + "]");
|
||||
}
|
||||
|
||||
if (suiteParent != null ) {
|
||||
final String parentFQName = JUnit4ReflectionUtil.getClassName(suiteParent);
|
||||
if (!myCurrentClassName.equals(parentFQName)) {
|
||||
if (parent != null) {
|
||||
List parents = (List)myParents.get(description);
|
||||
if (parents == null) {
|
||||
parents = new ArrayList();
|
||||
parents = new ArrayList(1);
|
||||
myParents.put(description, parents);
|
||||
}
|
||||
if (!parents.contains(parentFQName)) {
|
||||
parents.add(parentFQName);
|
||||
}
|
||||
|
||||
List descriptors = (List)mySuites.get(parentFQName);
|
||||
if (descriptors == null) {
|
||||
descriptors = new ArrayList();
|
||||
mySuites.put(parentFQName, descriptors);
|
||||
}
|
||||
descriptors.add(description);
|
||||
parents.add(pParents);
|
||||
}
|
||||
if (isWarning(methodName, className)) {
|
||||
className = JUnit4ReflectionUtil.getClassName(parent);
|
||||
}
|
||||
myPrintStream.println("##teamcity[suiteTreeNode name=\'" + escapeName(methodName) + "\' " + getTestMethodLocation(methodName, className) + "]");
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -292,8 +260,7 @@ public class SMTestSender extends RunListener {
|
||||
for (Iterator iterator = tests.iterator(); iterator.hasNext(); ) {
|
||||
final Object next = iterator.next();
|
||||
final Description nextDescription = (Description)next;
|
||||
final List childTests = nextDescription.getChildren();
|
||||
if ((myCurrentClassName == null || !myCurrentClassName.equals(className)) && !pass) {
|
||||
if ((myRootName == null || !myRootName.equals(className)) && !pass) {
|
||||
pass = true;
|
||||
String locationHint = className;
|
||||
if (isParameter((Description)description)) {
|
||||
@@ -308,7 +275,7 @@ public class SMTestSender extends RunListener {
|
||||
}
|
||||
myPrintStream.println("##teamcity[suiteTreeStarted name=\'" + escapeName(getShortName(className)) + "\' locationHint=\'java:suite://" + escapeName(locationHint) + "\']");
|
||||
}
|
||||
sendTree(nextDescription, description, isParameter(description) ? null : childTests.isEmpty() && parent != null ? parent : description);
|
||||
sendTree(nextDescription, description, pParents);
|
||||
}
|
||||
if (pass) {
|
||||
myPrintStream.println("##teamcity[suiteTreeEnded name=\'" + escapeName(getShortName(JUnit4ReflectionUtil.getClassName((Description)description))) + "\']");
|
||||
@@ -329,8 +296,8 @@ public class SMTestSender extends RunListener {
|
||||
}
|
||||
|
||||
public void sendTree(Description description) {
|
||||
myCurrentClassName = JUnit4ReflectionUtil.getClassName((Description)description);
|
||||
sendTree(description, null, null);
|
||||
myRootName = JUnit4ReflectionUtil.getClassName((Description)description);
|
||||
sendTree(description, null, new ArrayList());
|
||||
}
|
||||
|
||||
private static String getShortName(String fqName) {
|
||||
|
||||
@@ -24,16 +24,27 @@ import com.jetbrains.python.psi.PyStringLiteralExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author vlan
|
||||
*/
|
||||
public class PyTypingAnnotationInjector extends PyInjectorBase {
|
||||
public static final Pattern RE_TYPING_ANNOTATION = Pattern.compile("\\s*\\S+(\\[.*\\])?\\s*");
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Language getInjectedLanguage(@NotNull PsiElement context) {
|
||||
if (context instanceof PyStringLiteralExpression && PsiTreeUtil.getParentOfType(context, PyAnnotation.class, true) != null) {
|
||||
return PyDocstringLanguageDialect.getInstance();
|
||||
if (context instanceof PyStringLiteralExpression) {
|
||||
final PyStringLiteralExpression expr = (PyStringLiteralExpression)context;
|
||||
if (PsiTreeUtil.getParentOfType(context, PyAnnotation.class, true) != null && isTypingAnnotation(expr.getStringValue())) {
|
||||
return PyDocstringLanguageDialect.getInstance();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isTypingAnnotation(@NotNull String s) {
|
||||
return RE_TYPING_ANNOTATION.matcher(s).matches();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ public class PyContentEntriesEditor extends CommonContentEntriesEditor {
|
||||
}
|
||||
VirtualFilePointer root = getRoot(provider, folder);
|
||||
if (root != null) {
|
||||
provider.removeRoot(contentEntry, root);
|
||||
provider.removeRoot(contentEntry, root, getModel());
|
||||
fireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public abstract class PyRootTypeProvider {
|
||||
|
||||
public abstract boolean isMine(ContentFolder folder);
|
||||
|
||||
public void removeRoot(ContentEntry contentEntry, @NotNull final VirtualFilePointer root) {
|
||||
public void removeRoot(ContentEntry contentEntry, @NotNull final VirtualFilePointer root, ModifiableRootModel model) {
|
||||
getRoots().remove(contentEntry, root);
|
||||
}
|
||||
public abstract MultiMap<ContentEntry, VirtualFilePointer> getRoots();
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.ide.fileTemplates.FileTemplate;
|
||||
import com.intellij.ide.fileTemplates.FileTemplateManager;
|
||||
import com.intellij.ide.scratch.ScratchFileService;
|
||||
import com.intellij.injected.editor.VirtualFileWindow;
|
||||
import com.intellij.lang.ASTFactory;
|
||||
import com.intellij.lang.ASTNode;
|
||||
@@ -1803,6 +1804,16 @@ public class PyUtil {
|
||||
return type == builtinCache.getObjectType() || type == builtinCache.getOldstyleClassobjType();
|
||||
}
|
||||
|
||||
public static boolean isInScratchFile(@NotNull PsiElement element) {
|
||||
final ScratchFileService service = ScratchFileService.getInstance();
|
||||
final PsiFile file = element.getContainingFile();
|
||||
if (file != null) {
|
||||
final VirtualFile virtualFile = file.getVirtualFile();
|
||||
return service != null && virtualFile != null && service.getRootType(virtualFile) != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper class allows to collect various information about AST nodes composing {@link PyStringLiteralExpression}.
|
||||
*/
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil;
|
||||
import com.jetbrains.python.console.PydevConsoleRunner;
|
||||
import com.jetbrains.python.facet.PythonPathContributingFacet;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyUtil;
|
||||
import com.jetbrains.python.psi.impl.PyBuiltinCache;
|
||||
import com.jetbrains.python.psi.impl.PyImportResolver;
|
||||
import com.jetbrains.python.sdk.PySdkUtil;
|
||||
@@ -84,7 +85,7 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso
|
||||
@Override
|
||||
public QualifiedNameResolver fromElement(@NotNull PsiElement foothold) {
|
||||
myContext.setFromElement(foothold);
|
||||
if (PydevConsoleRunner.isInPydevConsole(foothold)) {
|
||||
if (PydevConsoleRunner.isInPydevConsole(foothold) || PyUtil.isInScratchFile(foothold)) {
|
||||
withAllModules();
|
||||
Sdk sdk = PydevConsoleRunner.getConsoleSdk(foothold);
|
||||
if (sdk != null) {
|
||||
|
||||
@@ -15,6 +15,15 @@
|
||||
*/
|
||||
package com.jetbrains.python;
|
||||
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiLanguageInjectionHost;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.jetbrains.python.documentation.PythonDocumentationProvider;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
@@ -25,6 +34,8 @@ import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tests for a type system based on mypy's typing module.
|
||||
*
|
||||
@@ -306,6 +317,59 @@ public class PyTypingTest extends PyTestCase {
|
||||
" pass\n");
|
||||
}
|
||||
|
||||
public void testStringLiteralInjection() {
|
||||
doTestInjectedText("class C:\n" +
|
||||
" def foo(self, expr: '<caret>C'):\n" +
|
||||
" pass\n",
|
||||
"C");
|
||||
}
|
||||
|
||||
public void testStringLiteralInjectionParameterizedType() {
|
||||
doTestInjectedText("from typing import Union, List\n" +
|
||||
"\n" +
|
||||
"class C:\n" +
|
||||
" def foo(self, expr: '<caret>Union[List[C], C]'):\n" +
|
||||
" pass\n",
|
||||
"Union[List[C], C]");
|
||||
}
|
||||
|
||||
// PY-15810
|
||||
public void testNoStringLiteralInjectionForNonTypingStrings() {
|
||||
doTestNoInjectedText("class C:\n" +
|
||||
" def foo(self, expr: '<caret>foo bar'):\n" +
|
||||
" pass\n");
|
||||
}
|
||||
|
||||
private void doTestNoInjectedText(@NotNull String text) {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, text);
|
||||
final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject());
|
||||
final PsiLanguageInjectionHost host = languageManager.getInjectionHost(getElementAtCaret());
|
||||
assertNull(host);
|
||||
}
|
||||
|
||||
private void doTestInjectedText(@NotNull String text, @NotNull String expected) {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, text);
|
||||
final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject());
|
||||
final PsiLanguageInjectionHost host = languageManager.getInjectionHost(getElementAtCaret());
|
||||
assertNotNull(host);
|
||||
final List<Pair<PsiElement, TextRange>> files = languageManager.getInjectedPsiFiles(host);
|
||||
assertNotNull(files);
|
||||
assertFalse(files.isEmpty());
|
||||
final PsiElement injected = files.get(0).getFirst();
|
||||
assertEquals(expected, injected.getText());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PsiElement getElementAtCaret() {
|
||||
final Editor editor = myFixture.getEditor();
|
||||
final Document document = editor.getDocument();
|
||||
final PsiFile file = PsiDocumentManager.getInstance(myFixture.getProject()).getPsiFile(document);
|
||||
assertNotNull(file);
|
||||
final PsiElement element = file.findElementAt(myFixture.getCaretOffset());
|
||||
assertNotNull(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
private void doTest(@NotNull String expectedType, @NotNull String text) {
|
||||
myFixture.copyDirectoryToProject("typing", "");
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, text);
|
||||
|
||||
@@ -448,6 +448,9 @@
|
||||
<applicationService serviceInterface="com.intellij.psi.JavaDirectoryService"
|
||||
serviceImplementation="com.intellij.psi.impl.file.JavaDirectoryServiceImpl"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.psi.util.JavaClassSupers"
|
||||
serviceImplementation="com.intellij.psi.impl.JavaClassSupersImpl"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.openapi.projectRoots.JavaVersionService"
|
||||
serviceImplementation="com.intellij.openapi.projectRoots.JavaVersionServiceImpl"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user