Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2015-05-08 19:30:07 +02:00
57 changed files with 1541 additions and 384 deletions
@@ -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;
}
}
@@ -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;
@@ -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");
@@ -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'
@@ -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
@@ -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);
@@ -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);
}
+3 -4
View File
@@ -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();
}
@@ -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) {
@@ -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() {
@@ -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;
}
}
}
@@ -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");
}
}
@@ -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);
+3
View File
@@ -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"/>