Merge remote-tracking branch 'origin/master'

This commit is contained in:
Roman Shevchenko
2015-12-02 16:03:15 +01:00
39 changed files with 473 additions and 84 deletions
@@ -214,6 +214,11 @@ public class FieldEvaluator implements Evaluator {
return modifier;
}
@Override
public String toString() {
return "field " + myFieldName;
}
private static final class FQNameClassFilter implements TargetClassFilter {
private final String myQName;
@@ -360,11 +360,8 @@ public class GenericsHighlightUtil {
Map<PsiClass, PsiSubstitutor> inheritedClasses,
Set<PsiClass> visited,
TextRange textRange) {
final PsiClassType[] superTypes = aClass.getSuperTypes();
for (PsiClassType superType : superTypes) {
superType = PsiClassImplUtil.correctType(superType, place.getResolveScope());
if (superType == null) continue;
final PsiClassType.ClassResolveResult result = ((PsiClassType)PsiUtil.captureToplevelWildcards(superType, place)).resolveGenerics();
final List<PsiClassType.ClassResolveResult> superTypes = PsiClassImplUtil.getScopeCorrectedSuperTypes(aClass, place.getResolveScope());
for (PsiClassType.ClassResolveResult result : superTypes) {
final PsiClass superClass = result.getElement();
if (superClass == null || visited.contains(superClass)) continue;
PsiSubstitutor superTypeSubstitutor = result.getSubstitutor();
@@ -732,7 +732,7 @@ public class PsiClassImplUtil {
return new TypeCorrector(resolveScope).correctType(originalType);
}
private static List<PsiClassType.ClassResolveResult> getScopeCorrectedSuperTypes(final PsiClass aClass, GlobalSearchScope resolveScope) {
public static List<PsiClassType.ClassResolveResult> getScopeCorrectedSuperTypes(final PsiClass aClass, GlobalSearchScope resolveScope) {
Map<GlobalSearchScope, List<PsiClassType.ClassResolveResult>> cache =
CachedValuesManager.getCachedValue(aClass, new CachedValueProvider<Map<GlobalSearchScope, List<PsiClassType.ClassResolveResult>>>() {
@Nullable
@@ -46,7 +46,7 @@ public class PsiSuperMethodImplUtil {
@NotNull
@Override
public Map<MethodSignature, HierarchicalMethodSignature> fun(PsiClass dom) {
return buildMethodHierarchy(dom, null, PsiSubstitutor.EMPTY, true, new THashSet<PsiClass>(), false, dom.getResolveScope(), dom);
return buildMethodHierarchy(dom, null, PsiSubstitutor.EMPTY, true, new THashSet<PsiClass>(), false, dom.getResolveScope());
}
});
private static final PsiCacheKey<FactoryMap<String, Map<MethodSignature, HierarchicalMethodSignature>>, PsiClass> SIGNATURES_BY_NAME_KEY = PsiCacheKey
@@ -57,7 +57,7 @@ public class PsiSuperMethodImplUtil {
@Nullable
@Override
protected Map<MethodSignature, HierarchicalMethodSignature> create(String methodName) {
return buildMethodHierarchy(psiClass, methodName, PsiSubstitutor.EMPTY, true, new THashSet<PsiClass>(), false, psiClass.getResolveScope(), psiClass);
return buildMethodHierarchy(psiClass, methodName, PsiSubstitutor.EMPTY, true, new THashSet<PsiClass>(), false, psiClass.getResolveScope());
}
};
}
@@ -133,7 +133,7 @@ public class PsiSuperMethodImplUtil {
final boolean includePrivates,
@NotNull final Set<PsiClass> visited,
boolean isInRawContext,
GlobalSearchScope resolveScope, PsiElement place) {
GlobalSearchScope resolveScope) {
ProgressManager.checkCanceled();
Map<MethodSignature, HierarchicalMethodSignature> result = new LinkedHashMap<MethodSignature, HierarchicalMethodSignature>();
final Map<MethodSignature, List<PsiMethod>> sameParameterErasureMethods = new THashMap<MethodSignature, List<PsiMethod>>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
@@ -190,10 +190,9 @@ public class PsiSuperMethodImplUtil {
map.put(signature, newH);
}
for (PsiClassType superType : aClass.getSuperTypes()) {
superType = PsiClassImplUtil.correctType(superType, resolveScope);
if (superType == null) continue; //super class doesn't belong to resolve scope
PsiClassType.ClassResolveResult superTypeResolveResult = ((PsiClassType)PsiUtil.captureToplevelWildcards(superType, place)).resolveGenerics();
final List<PsiClassType.ClassResolveResult> superTypes = PsiClassImplUtil.getScopeCorrectedSuperTypes(aClass, resolveScope);
for (PsiClassType.ClassResolveResult superTypeResolveResult : superTypes) {
PsiClass superClass = superTypeResolveResult.getElement();
if (superClass == null) continue;
if (!visited.add(superClass)) continue; // cyclic inheritance
@@ -201,7 +200,7 @@ public class PsiSuperMethodImplUtil {
PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superSubstitutor, substitutor, isInRawContext);
final boolean isInRawContextSuper = (isInRawContext || PsiUtil.isRawSubstitutor(superClass, superSubstitutor)) && superClass.getTypeParameters().length != 0;
Map<MethodSignature, HierarchicalMethodSignature> superResult = buildMethodHierarchy(superClass, nameHint, finalSubstitutor, false, visited, isInRawContextSuper, resolveScope, place);
Map<MethodSignature, HierarchicalMethodSignature> superResult = buildMethodHierarchy(superClass, nameHint, finalSubstitutor, false, visited, isInRawContextSuper, resolveScope);
visited.remove(superClass);
List<Pair<MethodSignature, HierarchicalMethodSignature>> flattened = new ArrayList<Pair<MethodSignature, HierarchicalMethodSignature>>();
@@ -651,7 +651,7 @@ public class InferenceSession {
final PsiSubstitutor substitutor = resolveSubset(Collections.singletonList(inferenceVariable), mySiteSubstitutor);
final PsiType substitutedReturnType = substitutor.substitute(inferenceVariable.getParameter());
if (substitutedReturnType != null) {
addConstraint(new TypeCompatibilityConstraint(targetType, PsiUtil.captureToplevelWildcards(substitutedReturnType, (PsiExpression)myContext)));
addConstraint(new TypeCompatibilityConstraint(targetType, PsiUtil.captureToplevelWildcards(substitutedReturnType, myContext)));
}
}
else {
@@ -662,7 +662,7 @@ public class InferenceSession {
LOG.assertTrue(returnType instanceof PsiClassType);
PsiClassType substitutedCapture = (PsiClassType)returnType;
if (!toplevel) {
substitutedCapture = (PsiClassType)PsiUtil.captureToplevelWildcards(returnType, (PsiExpression)myContext);
substitutedCapture = (PsiClassType)PsiUtil.captureToplevelWildcards(returnType, myContext);
final PsiTypeParameter[] typeParameters = psiClass.getTypeParameters();
final InferenceVariable[] copy = initBounds(null, typeParameters);
@@ -0,0 +1,12 @@
interface Msg<T extends Msg<T>> {}
class Conv<T extends Msg<T>> {
static <A extends Msg<A>> Conv<A> createBar(A a) {
return null;
}
@SuppressWarnings("unchecked")
static void test() {
Conv<? extends Msg<?>> conv = Conv.createBar((Msg) null);
}
}
@@ -0,0 +1,24 @@
import java.util.List;
import java.util.function.Function;
import static java.util.Arrays.asList;
class Test {
public static void bar(List<? extends Number> parameters, Function<Object, String> function)
{
Iterable<String> objects = transform(checkNotNull(parameters), function);
}
public static <T> T checkNotNull(T reference) {
return reference;
}
public static <F, T> List<T> transform(final List<F> fromIterable, final Function<? super F, ? extends T> function) {
return null;
}
{
List<List<List<Integer>>> list = asList(asList(asList(1)), asList(asList(2)));
}
}
@@ -0,0 +1,9 @@
import java.util.List;
interface A<T extends List<String>> { }
class C {
List<A<?>> foo(List<A<? extends Iterable<?>>> x) {
return x;
}
}
@@ -0,0 +1,10 @@
import java.util.List;
interface A<T extends A<T> & Cloneable> { }
class C {
List<A<? extends A<?>>> foo(List<A<?>> x) {
return x;
}
}
@@ -0,0 +1,11 @@
class Test {
void bar() {
baz<error descr="'baz(S)' in 'Test' cannot be applied to '(java.io.Serializable & java.lang.Comparable<? extends java.io.Serializable & java.lang.Comparable<? extends java.lang.Comparable<?>>>)'">(foo(1, ""))</error>;
}
<T> T foo(T x, T y) {
return x;
}
<S extends Comparable<S>> void baz(S x) { }
}
@@ -0,0 +1,28 @@
import java.util.function.Consumer;
class Foo {
static <E extends Element> void add(Klass<?> klass, E e, Consumer<E> action) {}
static <T> void bar(Klass<?> k, Method<T> m) {
add(k, m, k::addMethod);
}
}
interface Element {}
interface Method<M> extends Element {}
interface Type<T> {
<M, C extends Type<T>> C addMethod(Method<M> m);
}
interface Klass<T> extends Type<T> {}
//simplified
class Foo1 {
static void bar(Type1<?> k) {
k.addMethod();
}
}
interface Type1<T> {
<C extends Type1<T>> C addMethod();
}
@@ -0,0 +1,26 @@
import java.util.LinkedList;
import java.util.List;
class MyTest {
private Test<LinkedList> alist;
public Test<LinkedList> getAlist() {
return alist = create(Test::new, alist);
}
private <T> T create(CreateCallback<T> callback, T defaultVal) {
if (defaultVal == null) {
return callback.create();
}
return defaultVal;
}
interface CreateCallback<T> {
T create();
}
class Test<E extends List> {}
}
@@ -0,0 +1,21 @@
abstract class WrapperOne<T> {
public abstract <X> WrapperOne<X> reformChain(Reformer<? extends WrapperTwo<? extends X>> reformer);
}
interface WrapperTwo<T> {}
interface Reformer<T> {
T reform();
}
class ReformerClient {
public WrapperOne<String> sampleChainA(WrapperOne<String> p, Reformer<WrapperTwo<String>> r) {
return p.reformChain(r::reform);
}
public WrapperOne<String> sampleChainB(WrapperOne<String> p, Reformer<? extends WrapperTwo<String>> r) {
return p.reformChain(r::reform);
}
public WrapperOne<String> sampleChainC(WrapperOne<String> p, Reformer<? extends WrapperTwo<String>> r) {
return p.reformChain(r);
}
}
@@ -0,0 +1,7 @@
package p;
abstract class B {
void foo(A<?> a)
{
a.get().<error descr="Cannot resolve method 'reversed()'">reversed</error>();
}
}
@@ -0,0 +1,4 @@
package p;
public abstract class A <T extends java.util.Comparator> {
public abstract T get();
}
@@ -124,6 +124,11 @@ public class MultipleJdksHighlightingTest extends UsefulTestCase {
doTestWithoutLibrary();
}
public void testWrongComparatorInUpperBound() throws Exception {
addDependencies_37_78();
doTestWithoutLibrary();
}
public void testGenericComparator() throws Exception {
addDependencies_37_78();
doTestWithoutLibrary();
@@ -28,6 +28,7 @@ import com.intellij.testFramework.IdeaTestUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
//javac option to dump bounds: -XDdumpInferenceGraphsTo=
public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
@NonNls private static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/genericsHighlighting8";
@@ -885,4 +886,28 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
public void testIDEA148348() throws Exception {
doTest();
}
public void testIDEA148361() throws Exception {
doTest();
}
public void testIDEA134059() throws Exception {
doTest();
}
public void testIDEA139222() throws Exception {
doTest();
}
public void testIDEA139156() throws Exception {
doTest();
}
public void testIDEA139169() throws Exception {
doTest();
}
public void testIDEA131686() throws Exception {
doTest();
}
}
@@ -236,6 +236,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testIDEA136325() throws Exception {
doTest();
}
private void doTest() {
doTest(false);
}
@@ -462,6 +462,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testIDEA148093() throws Exception {
doTest();
}
private void doTest() {
doTest(false);
}
@@ -29,6 +29,7 @@ import org.jetbrains.jps.incremental.Utils;
import org.jetbrains.jps.incremental.artifacts.ArtifactBuildTargetType;
import org.jetbrains.jps.incremental.fs.BuildFSState;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
import org.jetbrains.jps.model.JpsModel;
import java.io.File;
@@ -214,12 +215,20 @@ public class Standalone {
@Override
public void processMessage(BuildMessage msg) {
String messageText = msg.getMessageText();
String messageText;
if (msg instanceof CompilerMessage) {
CompilerMessage compilerMessage = (CompilerMessage) msg;
messageText = compilerMessage.getSourcePath() + "(" + compilerMessage.getLine() + ":" + compilerMessage.getColumn() + "): " + msg.getMessageText();
}
else {
messageText = msg.getMessageText();
}
if (messageText.isEmpty()) return;
if (msg.getKind() == BuildMessage.Kind.ERROR) {
System.err.println("Error: " + messageText);
hasErrors = true;
}
else if (msg.getKind() != BuildMessage.Kind.PROGRESS || !messageText.startsWith("Compiled") && !messageText.startsWith("Copying")) {
System.out.println(messageText);
}
@@ -475,4 +475,44 @@ public class DvcsUtil {
}
});
}
@NotNull
public static String joinShortNames(@NotNull Collection<? extends Repository> repositories) {
return joinShortNames(repositories, -1);
}
@NotNull
public static String joinShortNames(@NotNull Collection<? extends Repository> repositories, int limit) {
return joinWithAnd(ContainerUtil.map(repositories, new Function<Repository, String>() {
@Override
public String fun(@NotNull Repository repository) {
return getShortRepositoryName(repository);
}
}), limit);
}
@NotNull
private static String joinWithAnd(@NotNull List<String> strings, int limit) {
int size = strings.size();
if (size == 0) return "";
if (size == 1) return strings.get(0);
if (size == 2) return strings.get(0) + " and " + strings.get(1);
boolean isLimited = limit >= 2 && limit < size;
int listCount = isLimited ? limit - 1 : size - 1;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < listCount; i++) {
if (i != 0) sb.append(", ");
sb.append(strings.get(i));
}
if (isLimited) {
sb.append(" and ").append(size - limit + 1).append(" others");
}
else {
sb.append(" and ").append(strings.get(size - 1));
}
return sb.toString();
}
}
@@ -74,9 +74,10 @@ public class CommentByLineCommentHandler extends MultiCaretCodeInsightActionHand
PsiElement context = InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(file);
if (context != null && (context.textContains('\'') || context.textContains('\"') || context.textContains('/'))) {
if (context != null && (context.textContains('\'') || context.textContains('\"') || context.textContains('/') || context.textContains('`'))) {
String s = context.getText();
if (StringUtil.startsWith(s, "\"") || StringUtil.startsWith(s, "\'") || StringUtil.startsWith(s, "/")) {
if (StringUtil.startsWith(s, "\"") || StringUtil.startsWith(s, "\'") || StringUtil.startsWith(s, "/")
|| StringUtil.startsWith(s, "`")) {
file = context.getContainingFile();
editor = editor instanceof EditorWindow ? ((EditorWindow)editor).getDelegate() : editor;
caret = caret instanceof InjectedCaret ? ((InjectedCaret)caret).getDelegate() : caret;
@@ -22,6 +22,7 @@ import junit.framework.TestCase;
import javax.swing.*;
import java.io.File;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
/**
@@ -75,7 +76,8 @@ public class _FirstInSuiteTest extends TestCase {
Class.forName("com.sun.jna.Native");
String tempDirectory = FileUtilRt.getTempDirectory();
System.out.println("FileUtil.getTempDirectory() = " + tempDirectory + " ("+new File(tempDirectory).list().length+" files)");
String[] list = new File(tempDirectory).list();
System.out.println("FileUtil.getTempDirectory() = " + tempDirectory + " (" + list.length + " files): " + Arrays.asList(list));
}
// performance tests
@@ -116,6 +116,7 @@ public class ChunkExtractor {
Project project = file.getProject();
myDocument = PsiDocumentManager.getInstance(project).getDocument(file);
LOG.assertTrue(myDocument != null);
final FileType fileType = file.getFileType();
SyntaxHighlighter highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(fileType, project, file.getVirtualFile());
highlighter = highlighter == null ? new PlainSyntaxHighlighter() : highlighter;
@@ -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.
@@ -520,13 +520,12 @@ public class UsageInfo2UsageAdapter implements UsageInModule,
PsiFile file = getPsiFile();
if (file != null) {
ChunkExtractor extractor = ChunkExtractor.getExtractor(file);
Segment segment = getFirstSegment();
if (segment != null) {
Document document = PsiDocumentManager.getInstance(getProject()).getDocument(file);
if (document != null) {
ChunkExtractor extractor = ChunkExtractor.getExtractor(file);
SmartList<TextChunk> chunks = new SmartList<TextChunk>();
extractor.createTextChunks(
this,
@@ -17,6 +17,7 @@ package com.intellij.openapi.vcs;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -39,7 +40,7 @@ public abstract class VcsTaskHandler {
return handlers.toArray(new VcsTaskHandler[handlers.size()]);
}
public static class TaskInfo {
public static class TaskInfo implements Comparable<TaskInfo> {
private final String myBranch;
private final Collection<String> myRepositories;
@@ -61,6 +62,11 @@ public abstract class VcsTaskHandler {
public String toString() {
return getName();
}
@Override
public int compareTo(TaskInfo o) {
return Comparing.compare(myBranch, o.myBranch);
}
}
private static final ExtensionPointName<VcsTaskHandler> EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.vcs.taskHandler");
@@ -65,6 +65,7 @@ import java.io.UnsupportedEncodingException;
import java.util.*;
import static com.intellij.dvcs.DvcsUtil.getShortRepositoryName;
import static com.intellij.dvcs.DvcsUtil.joinShortNames;
/**
* Git utility/helper methods
@@ -1025,4 +1026,15 @@ public class GitUtil {
public static String mention(@NotNull GitRepository repository) {
return getRepositoryManager(repository.getProject()).moreThanOneRoot() ? " in " + getShortRepositoryName(repository) : "";
}
@NotNull
public static String mention(@NotNull Collection<GitRepository> repositories) {
return mention(repositories, -1);
}
@NotNull
public static String mention(@NotNull Collection<GitRepository> repositories, int limit) {
if (repositories.isEmpty()) return "";
return " in " + joinShortNames(repositories, limit);
}
}
@@ -59,6 +59,7 @@ abstract class GitBranchOperation {
private final GitVcsSettings mySettings;
@NotNull private final Collection<GitRepository> mySuccessfulRepositories;
@NotNull private final Collection<GitRepository> mySkippedRepositories;
@NotNull private final Collection<GitRepository> myRemainingRepositories;
protected GitBranchOperation(@NotNull Project project, @NotNull GitPlatformFacade facade, @NotNull Git git,
@@ -76,6 +77,7 @@ abstract class GitBranchOperation {
}
});
mySuccessfulRepositories = new ArrayList<GitRepository>();
mySkippedRepositories = new ArrayList<GitRepository>();
myRemainingRepositories = new ArrayList<GitRepository>(myRepositories);
mySettings = myFacade.getSettings(myProject);
}
@@ -123,18 +125,37 @@ abstract class GitBranchOperation {
}
}
/**
* Marks repositories as successful, i.e. they won't be handled again.
*/
protected void markSkip(GitRepository... repositories) {
for (GitRepository repository : repositories) {
mySkippedRepositories.add(repository);
myRemainingRepositories.remove(repository);
}
}
/**
* @return true if the operation has already succeeded in at least one of repositories.
*/
protected boolean wereSuccessful() {
return !mySuccessfulRepositories.isEmpty();
}
protected boolean wereSkipped() {
return !mySkippedRepositories.isEmpty();
}
@NotNull
protected Collection<GitRepository> getSuccessfulRepositories() {
return mySuccessfulRepositories;
}
@NotNull
protected Collection<GitRepository> getSkippedRepositories() {
return mySkippedRepositories;
}
@NotNull
protected String successfulRepositoriesJoined() {
return GitUtil.joinToHtml(mySuccessfulRepositories);
@@ -94,12 +94,12 @@ public final class GitBranchWorker {
public void checkoutNewBranchStartingFrom(@NotNull String newBranchName, @NotNull String startPoint,
@NotNull List<GitRepository> repositories) {
updateInfo(repositories);
new GitCheckoutOperation(myProject, myFacade, myGit, myUiHandler, repositories, startPoint, false, newBranchName).execute();
new GitCheckoutOperation(myProject, myFacade, myGit, myUiHandler, repositories, startPoint, false, true, newBranchName).execute();
}
public void checkout(@NotNull final String reference, boolean detach, @NotNull List<GitRepository> repositories) {
updateInfo(repositories);
new GitCheckoutOperation(myProject, myFacade, myGit, myUiHandler, repositories, reference, detach, null).execute();
new GitCheckoutOperation(myProject, myFacade, myGit, myUiHandler, repositories, reference, detach, false, null).execute();
}
@@ -16,6 +16,8 @@
package git4idea.branch;
import com.intellij.dvcs.DvcsUtil;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
@@ -33,6 +35,7 @@ import git4idea.util.GitPreservingProcess;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.HyperlinkEvent;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -54,6 +57,7 @@ class GitCheckoutOperation extends GitBranchOperation {
@NotNull private final String myStartPointReference;
private final boolean myDetach;
private final boolean myRefShouldBeValid;
@Nullable private final String myNewBranch;
GitCheckoutOperation(@NotNull Project project,
@@ -63,10 +67,12 @@ class GitCheckoutOperation extends GitBranchOperation {
@NotNull Collection<GitRepository> repositories,
@NotNull String startPointReference,
boolean detach,
boolean refShouldBeValid,
@Nullable String newBranch) {
super(project, facade, git, uiHandler, repositories);
myStartPointReference = startPointReference;
myDetach = detach;
myRefShouldBeValid = refShouldBeValid;
myNewBranch = newBranch;
}
@@ -83,11 +89,12 @@ class GitCheckoutOperation extends GitBranchOperation {
GitLocalChangesWouldBeOverwrittenDetector localChangesDetector =
new GitLocalChangesWouldBeOverwrittenDetector(root, GitLocalChangesWouldBeOverwrittenDetector.Operation.CHECKOUT);
GitSimpleEventDetector unmergedFiles = new GitSimpleEventDetector(GitSimpleEventDetector.Event.UNMERGED_PREVENTING_CHECKOUT);
GitSimpleEventDetector unknownPathspec = new GitSimpleEventDetector(GitSimpleEventDetector.Event.INVALID_REFERENCE);
GitUntrackedFilesOverwrittenByOperationDetector untrackedOverwrittenByCheckout =
new GitUntrackedFilesOverwrittenByOperationDetector(root);
GitCommandResult result = myGit.checkout(repository, myStartPointReference, myNewBranch, false, myDetach,
localChangesDetector, unmergedFiles, untrackedOverwrittenByCheckout);
localChangesDetector, unmergedFiles, unknownPathspec, untrackedOverwrittenByCheckout);
if (result.success()) {
refresh(repository);
markSuccessful(repository);
@@ -106,6 +113,9 @@ class GitCheckoutOperation extends GitBranchOperation {
fatalUntrackedFilesError(repository.getRoot(), untrackedOverwrittenByCheckout.getRelativeFilePaths());
fatalErrorHappened = true;
}
else if (!myRefShouldBeValid && unknownPathspec.hasHappened()) {
markSkip(repository);
}
else {
fatalError(getCommonErrorTitle(), result.getErrorOutputAsJoinedString());
fatalErrorHappened = true;
@@ -117,8 +127,27 @@ class GitCheckoutOperation extends GitBranchOperation {
}
if (!fatalErrorHappened) {
notifySuccess();
updateRecentBranch();
if (wereSuccessful()) {
if (!wereSkipped()) {
notifySuccess();
updateRecentBranch();
}
else {
String mentionSuccess = getSuccessMessage() + GitUtil.mention(getSuccessfulRepositories(), 4);
String mentionSkipped = wereSkipped() ? "<br>Revision not found" + GitUtil.mention(getSkippedRepositories(), 4) : "";
VcsNotifier.getInstance(myProject).notifySuccess("",
mentionSuccess +
mentionSkipped +
"<br><a href='rollback'>Rollback</a>",
new RollbackOperationNotificationListener());
updateRecentBranch();
}
}
else {
LOG.assertTrue(!myRefShouldBeValid);
notifyError("Couldn't checkout " + myStartPointReference, "Revision not found" + GitUtil.mention(getSkippedRepositories(), 4));
}
}
}
@@ -261,4 +290,14 @@ class GitCheckoutOperation extends GitBranchOperation {
repository.update();
}
}
private class RollbackOperationNotificationListener implements NotificationListener {
@Override
public void hyperlinkUpdate(@NotNull Notification notification,
@NotNull HyperlinkEvent event) {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED && event.getDescription().equalsIgnoreCase("rollback")) {
rollback();
}
}
}
}
@@ -273,6 +273,7 @@ public class GitImpl implements Git {
else { // checkout reference as new branch
h.addParameters("-b", newBranch, reference);
}
h.endOptions();
for (GitLineHandlerListener listener : listeners) {
h.addLineListener(listener);
}
@@ -35,7 +35,8 @@ public class GitSimpleEventDetector implements GitLineHandlerListener {
BRANCH_NOT_FULLY_MERGED("is not fully merged"),
MERGE_CONFLICT("Automatic merge failed; fix conflicts and then commit the result"),
MERGE_CONFLICT_ON_UNSTASH("conflict"),
ALREADY_UP_TO_DATE("Already up-to-date");
ALREADY_UP_TO_DATE("Already up-to-date"),
INVALID_REFERENCE("invalid reference:");
private final String myDetectionString;
@@ -26,7 +26,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vcs.VcsNotifier;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import git4idea.DialogManager;
import git4idea.GitPlatformFacade;
@@ -41,7 +40,6 @@ import git4idea.util.GitFreezingProcess;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -82,7 +80,7 @@ class GitAbortRebaseProcess {
void abortWithConfirmation() {
LOG.debug("Abort rebase. " + (myRepositoryToAbort == null ? "Nothing to abort" : getShortRepositoryName(myRepositoryToAbort)) +
". Roots to rollback: " + mention(myRepositoriesToRollback.keySet()));
". Roots to rollback: " + DvcsUtil.joinShortNames(myRepositoriesToRollback.keySet()));
final Ref<AbortChoice> ref = Ref.create();
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@Override
@@ -113,7 +111,7 @@ class GitAbortRebaseProcess {
}
else {
String message = "Do you want just to abort rebase" + GitUtil.mention(myRepositoryToAbort) + ",\n" +
"or also rollback the successful rebase in " + mention(myRepositoriesToRollback.keySet()) + "?";
"or also rollback the successful rebase" + GitUtil.mention(myRepositoriesToRollback.keySet()) + "?";
int choice = DialogManager.showYesNoCancelDialog(myProject, message, title, "Abort & Rollback", "Abort",
getCancelButtonText(), getQuestionIcon());
if (choice == Messages.YES) {
@@ -129,7 +127,7 @@ class GitAbortRebaseProcess {
LOG.error(new Throwable());
}
else {
String description = "Do you want rollback the successful rebase in " + mention(myRepositoriesToRollback.keySet()) + "?";
String description = "Do you want rollback the successful rebase" + GitUtil.mention(myRepositoriesToRollback.keySet()) + "?";
int choice = DialogManager.showOkCancelDialog(myProject, description, title, "Rollback", getCancelButtonText(), getQuestionIcon());
if (choice == Messages.YES) {
return AbortChoice.ROLLBACK_AND_ABORT;
@@ -198,29 +196,4 @@ class GitAbortRebaseProcess {
}
markDirtyAndRefresh(false, true, false, toVirtualFileArray(getRootsFromRepositories(toRefresh)));
}
@NotNull
private static String mention(@NotNull Collection<GitRepository> repositories) {
return joinWithAnd(ContainerUtil.map(repositories, new Function<GitRepository, String>() {
@Override
public String fun(@NotNull GitRepository repository) {
return getShortRepositoryName(repository);
}
}));
}
@NotNull
private static String joinWithAnd(@NotNull List<String> strings) {
int size = strings.size();
if (size == 0) return "";
if (size == 1) return strings.get(0);
if (size == 2) return strings.get(0) + " and " + strings.get(1);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size - 2; i++) {
sb.append(strings.get(i)).append(", ");
}
sb.append(strings.get(size - 2)).append(" and ").append(strings.get(size - 1));
return sb.toString();
}
}
@@ -105,6 +105,7 @@ class GitBranchPopup extends DvcsBranchPopup<GitRepository> {
@NotNull AbstractRepositoryManager<GitRepository> repositoryManager) {
List<GitRepository> allRepositories = repositoryManager.getRepositories();
popupGroup.add(new GitBranchPopupActions.GitNewBranchAction(myProject, allRepositories));
popupGroup.add(new GitBranchPopupActions.CheckoutRevisionActions(myProject, allRepositories));
popupGroup.addAll(createRepositoriesActions());
@@ -24,6 +24,8 @@ import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Condition;
import com.intellij.util.containers.ContainerUtil;
import git4idea.GitBranch;
import git4idea.branch.GitBranchUtil;
import git4idea.branch.GitBrancher;
@@ -50,9 +52,10 @@ class GitBranchPopupActions {
ActionGroup createActions(@Nullable DefaultActionGroup toInsert) {
DefaultActionGroup popupGroup = new DefaultActionGroup(null, false);
List<GitRepository> repositoryList = Collections.singletonList(myRepository);
popupGroup.addAction(new GitNewBranchAction(myProject,Collections.singletonList(myRepository)));
popupGroup.addAction(new CheckoutRevisionActions(myProject, myRepository));
popupGroup.addAction(new GitNewBranchAction(myProject, repositoryList));
popupGroup.addAction(new CheckoutRevisionActions(myProject, repositoryList));
if (toInsert != null) {
popupGroup.addAll(toInsert);
@@ -63,7 +66,7 @@ class GitBranchPopupActions {
Collections.sort(localBranches);
for (GitBranch localBranch : localBranches) {
if (!localBranch.equals(myRepository.getCurrentBranch())) { // don't show current branch in the list
popupGroup.add(new LocalBranchActions(myProject, Collections.singletonList(myRepository), localBranch.getName(), myRepository));
popupGroup.add(new LocalBranchActions(myProject, repositoryList, localBranch.getName(), myRepository));
}
}
@@ -71,7 +74,7 @@ class GitBranchPopupActions {
List<GitBranch> remoteBranches = new ArrayList<GitBranch>(myRepository.getBranches().getRemoteBranches());
Collections.sort(remoteBranches);
for (GitBranch remoteBranch : remoteBranches) {
popupGroup.add(new RemoteBranchActions(myProject, Collections.singletonList(myRepository), remoteBranch.getName(), myRepository));
popupGroup.add(new RemoteBranchActions(myProject, repositoryList, remoteBranch.getName(), myRepository));
}
return popupGroup;
@@ -97,14 +100,14 @@ class GitBranchPopupActions {
/**
* Checkout manually entered tag or revision number.
*/
private static class CheckoutRevisionActions extends DumbAwareAction {
public static class CheckoutRevisionActions extends DumbAwareAction {
private final Project myProject;
private final GitRepository myRepository;
private final List<GitRepository> myRepositories;
CheckoutRevisionActions(Project project, GitRepository repository) {
super("Checkout Tag or Revision");
CheckoutRevisionActions(Project project, List<GitRepository> repositories) {
super("Checkout Tag or Revision...");
myProject = project;
myRepository = repository;
myRepositories = repositories;
}
@Override public void actionPerformed(AnActionEvent e) {
@@ -114,14 +117,20 @@ class GitBranchPopupActions {
.showInputDialog(myProject, "Enter reference (branch, tag) name or commit hash", "Checkout", Messages.getQuestionIcon());
if (reference != null) {
GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
brancher.checkout(reference, true, Collections.singletonList(myRepository), null);
brancher.checkout(reference, true, myRepositories, null);
reportUsage("git.branch.checkout.revision");
}
}
@Override
public void update(AnActionEvent e) {
if (myRepository.isFresh()) {
boolean isFresh = ContainerUtil.and(myRepositories, new Condition<GitRepository>() {
@Override
public boolean value(GitRepository repository) {
return repository.isFresh();
}
});
if (isFresh) {
e.getPresentation().setEnabled(false);
e.getPresentation().setDescription("Checkout is not possible before the first commit");
}
@@ -218,6 +218,52 @@ public class GitBranchWorkerTest extends GitPlatformTest {
assertCurrentBranch(myContrib, "master");
}
public void test_checkout_revision_checkout_branch_with_complete_success() {
branchWithCommit(myRepositories, "feature");
checkoutRevision("feature", new TestUiHandler());
assertDetachedState("feature");
assertEquals("Notification about successful branch checkout is incorrect", "Checked out " + bcode("feature"),
myVcsNotifier.getLastNotification().getContent());
}
public void test_checkout_revision_checkout_ref_with_complete_success() {
branchWithCommit(myRepositories, "feature");
checkoutRevision("feature~1", new TestUiHandler());
assertDetachedState("master");
assertEquals("Notification about successful branch checkout is incorrect", "Checked out " + bcode("feature~1"),
myVcsNotifier.getLastNotification().getContent());
}
public void test_checkout_revision_checkout_ref_with_complete_failure() {
branchWithCommit(myRepositories, "feature");
checkoutRevision("unknown_ref", new TestUiHandler());
assertCurrentBranch("master");
assertCurrentRevision("master");
assertEquals("Notification about successful branch checkout is incorrect", "Revision not found in project, community and contrib",
myVcsNotifier.getLastNotification().getContent());
}
public void test_checkout_revision_checkout_ref_with_partial_success() {
branchWithCommit(ContainerUtil.list(myCommunity, myContrib), "feature");
checkoutRevision("feature", new TestUiHandler());
assertCurrentBranch(myUltimate, "master");
assertDetachedState(myCommunity, "feature");
assertDetachedState(myContrib, "feature");
assertEquals("Notification about successful branch checkout is incorrect",
"Checked out " + bcode("feature") + " in community and contrib" + "<br>" +
"Revision not found in project" + "<br><a href='rollback'>Rollback</a>",
myVcsNotifier.getLastNotification().getContent());
}
public void test_checkout_with_untracked_files_overwritten_by_checkout_in_first_repo_should_show_notification() {
test_untracked_files_overwritten_by_in_first_repo("checkout", 1);
}
@@ -807,14 +853,40 @@ public class GitBranchWorkerTest extends GitPlatformTest {
assertCurrentBranch(myContrib, "master");
}
static private void assertDetachedState(GitRepository repository, String reference) {
assertCurrentRevision(repository, reference);
String curBranch = getCurrentBranch(repository);
boolean isDetached = curBranch.contains("detached");
assertTrue("Current branch is not detached in ${repository} - " + curBranch, isDetached);
}
static private void assertCurrentBranch(GitRepository repository, String name) {
String curBranch = ObjectUtils.assertNotNull(ContainerUtil.find(git(repository, "branch").split("\n"), new Condition<String>() {
String curBranch = getCurrentBranch(repository);
assertEquals("Current branch is incorrect in ${repository}", name, curBranch);
}
@NotNull
private static String getCurrentBranch(GitRepository repository) {
return ObjectUtils.assertNotNull(ContainerUtil.find(git(repository, "branch").split("\n"), new Condition<String>() {
@Override
public boolean value(String s) {
return s.contains("*");
}
})).replace('*', ' ').trim();
assertEquals("Current branch is incorrect in ${repository}", name, curBranch);
}
static private void assertCurrentRevision(GitRepository repository, String reference) {
String expectedRef = git(repository, "rev-parse " + "HEAD");
String currentRef = git(repository, "rev-parse " + reference);
assertEquals("Current revision is incorrect in ${repository}", expectedRef, currentRef);
}
private void assertDetachedState(String reference) {
for (GitRepository repository : myRepositories) {
assertDetachedState(repository, reference);
}
}
private void assertCurrentBranch(String name) {
@@ -823,6 +895,12 @@ public class GitBranchWorkerTest extends GitPlatformTest {
}
}
private void assertCurrentRevision(String reference) {
for (GitRepository repository : myRepositories) {
assertCurrentRevision(repository, reference);
}
}
private void checkoutNewBranch(String name, GitBranchUiHandler uiHandler) {
GitBranchWorker brancher = new GitBranchWorker(myProject, myPlatformFacade, myGit, uiHandler);
brancher.checkoutNewBranch(name, myRepositories);
@@ -833,6 +911,11 @@ public class GitBranchWorkerTest extends GitPlatformTest {
brancher.checkout(name, false, myRepositories);
}
private void checkoutRevision(String reference, GitBranchUiHandler uiHandler) {
GitBranchWorker brancher = new GitBranchWorker(myProject, myPlatformFacade, myGit, uiHandler);
brancher.checkout(reference, true, myRepositories);
}
private void mergeBranch(String name, GitBranchUiHandler uiHandler) {
GitBranchWorker brancher = new GitBranchWorker(myProject, myPlatformFacade, myGit, uiHandler);
brancher.merge(name, GitBrancher.DeleteOnMergeOption.PROPOSE, myRepositories);
@@ -21,7 +21,6 @@ import com.intellij.rt.execution.junit.segments.PacketProcessor;
import junit.framework.*;
import junit.textui.ResultPrinter;
import junit.textui.TestRunner;
import org.junit.runner.notification.Failure;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -190,7 +189,12 @@ public class JUnit3IdeaTestRunner extends TestRunner implements IdeaTestRunner {
try {
final String trace = getTrace(failure);
ComparisonFailureData notification = null;
if (failure instanceof ComparisonFailure || failure.getClass().getName().equals("org.junit.ComparisonFailure")) {
if (failure instanceof FileComparisonFailure) {
final FileComparisonFailure comparisonFailure = (FileComparisonFailure)failure;
notification = new ComparisonFailureData(comparisonFailure.getExpected(), comparisonFailure.getActual(),
comparisonFailure.getFilePath(), comparisonFailure.getActualFilePath());
}
else if (failure instanceof ComparisonFailure || failure.getClass().getName().equals("org.junit.ComparisonFailure")) {
notification = new ComparisonFailureData(ComparisonDetailsExtractor.getExpected(failure), ComparisonDetailsExtractor.getActual(failure));
}
ComparisonFailureData.registerSMAttributes(notification, trace, failure.getMessage(), attrs, failure);
@@ -35,6 +35,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
@@ -92,9 +93,10 @@ public class EditTaskDialog extends DialogWrapper {
else {
VcsTaskHandler.TaskInfo[] tasks = handlers[0].getAllExistingTasks();
ArrayList<VcsTaskHandler.TaskInfo> infos = new ArrayList<VcsTaskHandler.TaskInfo>(Arrays.asList(tasks));
Collections.sort(infos);
infos.add(null);
myBranch.setModel(new CollectionComboBoxModel<VcsTaskHandler.TaskInfo>(infos));
final List<BranchInfo> branches = task.getBranches();
final List<BranchInfo> branches = task.getBranches(false);
if (!branches.isEmpty()) {
VcsTaskHandler.TaskInfo info = ContainerUtil.find(tasks, new Condition<VcsTaskHandler.TaskInfo>() {
@Override
@@ -45,7 +45,6 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
/**
* @author Dmitry Avdeev
@@ -135,12 +134,7 @@ public class OpenTaskDialog extends DialogWrapper {
VcsTaskHandler.TaskInfo[] tasks = handler.getAllExistingTasks();
if (tasks.length > 0) {
myVcsTaskHandler = handler;
Arrays.sort(tasks, new Comparator<VcsTaskHandler.TaskInfo>() {
@Override
public int compare(VcsTaskHandler.TaskInfo o1, VcsTaskHandler.TaskInfo o2) {
return o1.getName().compareTo(o2.getName());
}
});
Arrays.sort(tasks);
//noinspection unchecked
myBranchFrom.setModel(new DefaultComboBoxModel(tasks));
myBranchFrom.setEnabled(true);