Merge remote-tracking branch 'origin/master'

This commit is contained in:
Maxim.Mossienko
2015-01-07 14:17:20 +01:00
23 changed files with 356 additions and 181 deletions
@@ -211,6 +211,14 @@ public class RefJavaUtilImpl extends RefJavaUtil{
PsiMethod psiMethod = (PsiMethod)psiResolved;
RefMethodImpl refMethod = (RefMethodImpl)refResolved;
if (refExpression instanceof PsiMethodReferenceExpression) {
PsiType returnType = psiMethod.getReturnType();
if (!psiMethod.isConstructor() && returnType != PsiType.VOID) {
refMethod.setReturnValueUsed(true);
addTypeReference(psiFrom, returnType, refFrom.getRefManager());
}
return;
}
PsiMethodCallExpression call = PsiTreeUtil.getParentOfType(
refExpression,
PsiMethodCallExpression.class
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems/>
@@ -0,0 +1,13 @@
import java.util.function.Consumer;
import java.util.function.DoubleSupplier;
class B {
public void test(Consumer<DoubleSupplier> consumer) {
consumer.accept(this::method);
}
private double method() {
return 1;
}
}
@@ -12,6 +12,10 @@ package com.intellij.codeInspection;
import com.intellij.JavaTestUtil;
import com.intellij.codeInspection.unusedReturnValue.UnusedReturnValue;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.InspectionTestCase;
public class UnusedReturnValueTest extends InspectionTestCase {
@@ -39,7 +43,17 @@ public class UnusedReturnValueTest extends InspectionTestCase {
doTest();
}
public void testMethodReference() throws Exception {
doTest();
}
@Override
protected Sdk getTestProjectSdk() {
Sdk sdk = IdeaTestUtil.getMockJdk18();
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_8);
return sdk;
}
public void testSimpleSetter() throws Exception {
try {
myTool.IGNORE_BUILDER_PATTERN = true;
@@ -589,18 +589,6 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor {
}
private MatchingStrategy findStrategy(PsiElement el) {
// identify matching strategy
final MatchingHandler handler = myCompilingVisitor.getContext().getPattern().getHandler(el);
//if (handler instanceof SubstitutionHandler) {
// final SubstitutionHandler shandler = (SubstitutionHandler) handler;
if (handler.getFilter() instanceof SymbolNodeFilter ||
handler.getFilter() instanceof TypedSymbolNodeFilter
) {
return SymbolMatchingStrategy.getInstance();
}
//}
if (el instanceof PsiDocComment) {
return JavaDocMatchingStrategy.getInstance();
}
@@ -7,6 +7,27 @@ import com.intellij.psi.*;
*/
public class ExprMatchingStrategy extends MatchingStrategyBase {
@Override
public void visitTypeElement(PsiTypeElement type) {
result = true;
}
@Override public void visitReferenceParameterList(PsiReferenceParameterList psiReferenceParameterList) {
result = true;
}
@Override public void visitReferenceElement(PsiJavaCodeReferenceElement psiJavaCodeReferenceElement) {
result = true;
}
@Override public void visitTypeParameterList(PsiTypeParameterList psiTypeParameterList) {
result = true;
}
@Override public void visitReferenceList(final PsiReferenceList list) {
result = true;
}
@Override public void visitAnnotation(final PsiAnnotation annotation) {
result = true;
}
@@ -55,6 +76,11 @@ public class ExprMatchingStrategy extends MatchingStrategyBase {
result = true;
}
@Override
public void visitPackageStatement(PsiPackageStatement statement) {
result = true;
}
// finding parameters
@Override public void visitParameterList(final PsiParameterList list) {
result = true;
@@ -1,54 +0,0 @@
package com.intellij.structuralsearch.impl.matcher.strategies;
import com.intellij.psi.*;
/**
* CommonStrategy to match symbols
*/
public class SymbolMatchingStrategy extends ExprMatchingStrategy {
@Override public void visitReferenceList(final PsiReferenceList list) {
result = true;
}
@Override public void visitAnnotation(final PsiAnnotation annotation) {
result = true;
}
@Override public void visitAnnotationParameterList(final PsiAnnotationParameterList list) {
result = true;
}
@Override public void visitModifierList(final PsiModifierList list) {
result = true;
}
@Override public void visitNameValuePair(final PsiNameValuePair pair) {
result = true;
}
@Override public void visitTypeParameterList(PsiTypeParameterList psiTypeParameterList) {
result = true;
}
@Override public void visitTypeElement(PsiTypeElement psiTypeElement) {
result = true;
}
@Override public void visitReferenceElement(PsiJavaCodeReferenceElement psiJavaCodeReferenceElement) {
result = true;
}
@Override public void visitReferenceParameterList(PsiReferenceParameterList psiReferenceParameterList) {
result = true;
}
private SymbolMatchingStrategy() {}
private static class SymbolMatchingStrategyHolder {
private static final SymbolMatchingStrategy instance = new SymbolMatchingStrategy();
}
public static MatchingStrategy getInstance() {
return SymbolMatchingStrategyHolder.instance;
}
}
@@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.Function;
import org.jetbrains.annotations.Nullable;
public class MoveRenameUsageInfo extends UsageInfo{
@@ -90,18 +91,49 @@ public class MoveRenameUsageInfo extends UsageInfo{
public PsiReference getReference() {
if (myReference != null) {
final PsiElement element = myReference.getElement();
if (element != null && element.isValid()) return myReference;
if (element != null && element.isValid()) {
if (myReferenceRangeMarker == null) {
return myReference;
}
final PsiReference reference = checkReferenceRange(element, new Function<Integer, PsiReference>() {
@Override
public PsiReference fun(Integer start) {
return myReference;
}
});
if (reference != null) {
return reference;
}
}
}
if (myReferenceRangeMarker == null) return null;
final PsiElement element = getElement();
if (element == null) return null;
if (element == null || !element.isValid()) {
return null;
}
return checkReferenceRange(element, new Function<Integer, PsiReference>() {
@Override
public PsiReference fun(Integer start) {
return element.findReferenceAt(start);
}
});
}
@Nullable
private PsiReference checkReferenceRange(PsiElement element, Function<Integer, PsiReference> fn) {
final int start = myReferenceRangeMarker.getStartOffset() - element.getTextRange().getStartOffset();
final int end = myReferenceRangeMarker.getEndOffset() - element.getTextRange().getStartOffset();
final PsiReference reference = element.findReferenceAt(start);
if (reference == null) return null;
final PsiReference reference = fn.fun(start);
if (reference == null) {
return null;
}
final TextRange rangeInElement = reference.getRangeInElement();
if (rangeInElement.getStartOffset() != start || rangeInElement.getEndOffset() != end) return null;
if (rangeInElement.getStartOffset() != start || rangeInElement.getEndOffset() != end) {
return null;
}
return reference;
}
}
@@ -34,6 +34,7 @@ import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NotNull;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
@@ -55,9 +56,13 @@ public class CoreProjectLoader {
private static void loadDirectoryProject(MockProject project, VirtualFile projectDir) throws IOException, JDOMException,
InvalidDataException {
VirtualFile dotIdea = projectDir.findChild(Project.DIRECTORY_STORE_FOLDER);
assert dotIdea != null;
if (dotIdea == null)
throw new FileNotFoundException("Missing '" + Project.DIRECTORY_STORE_FOLDER + "' in " + projectDir.getPath());
VirtualFile modulesXml = dotIdea.findChild("modules.xml");
assert modulesXml != null;
if (modulesXml == null)
throw new FileNotFoundException("Missing 'modules.xml' in " + dotIdea.getPath());
StorageData storageData = loadStorageFile(project, modulesXml);
final Element moduleManagerState = storageData.getState("ProjectModuleManager");
if (moduleManagerState == null) {
@@ -67,7 +72,8 @@ public class CoreProjectLoader {
moduleManager.loadState(moduleManagerState);
VirtualFile miscXml = dotIdea.findChild("misc.xml");
assert miscXml != null;
if (miscXml == null)
throw new FileNotFoundException("Missing 'misc.xml' in " + dotIdea.getPath());
storageData = loadStorageFile(project, miscXml);
final Element projectRootManagerState = storageData.getState("ProjectRootManager");
if (projectRootManagerState == null) {
@@ -7,8 +7,10 @@ import org.jetbrains.concurrency.Promise;
import java.util.EventListener;
public interface BreakpointManager {
@NotNull
Breakpoint setBreakpoint(@NotNull BreakpointTarget target, int line, int column, @Nullable String condition, int ignoreCount, boolean enabled);
@NotNull
Promise<Void> remove(@NotNull Breakpoint breakpoint);
@Nullable
@@ -60,6 +60,7 @@ public abstract class BreakpointManagerBase<T extends BreakpointBase<?>> impleme
protected abstract Promise<Breakpoint> doSetBreakpoint(@NotNull BreakpointTarget target, @NotNull T breakpoint);
@NotNull
@Override
public Breakpoint setBreakpoint(@NotNull final BreakpointTarget target, int line, int column, @Nullable String condition, int ignoreCount, boolean enabled) {
final T breakpoint = createBreakpoint(target, line, column, condition, ignoreCount, enabled);
@@ -81,6 +82,7 @@ public abstract class BreakpointManagerBase<T extends BreakpointBase<?>> impleme
return breakpoint;
}
@NotNull
@Override
public Promise<Void> remove(@NotNull Breakpoint breakpoint) {
@SuppressWarnings("unchecked")
@@ -131,4 +133,10 @@ public abstract class BreakpointManagerBase<T extends BreakpointBase<?>> impleme
public FunctionSupport getFunctionSupport() {
return null;
}
@Nullable
@Override
public ScriptRegExpSupport getScriptRegExpSupport() {
return null;
}
}
@@ -2445,12 +2445,22 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
"}\n";
assertEquals("Find all annotations", 4, findMatchesCount(source2, "@'_Annotation"));
String source3 = "class A {\n" +
String source3 = "class A<@HH T> extends @HH Object {\n" +
" @HH final String s = (@HH String) new @HH Object();\n" +
" final String t = (String) new Object();\n" +
" Map<@HH String, @HH List<@HH String>> map;\n" +
"}\n";
assertEquals("Find annotated casts", 1, findMatchesCount(source3, "(@'_A 'Cast) '_Expression"));
assertEquals("Find annotated new expressions", 1, findMatchesCount(source3, "new @'_A 'Type()"));
assertEquals("Find all annotations 2", 8, findMatchesCount(source3, "@'_Annotation"));
// package-info.java
final String source4 = "/**\n" +
" * documentation\n" +
" */\n" +
"@Deprecated\n" +
"package one.two;";
assertEquals("Find annotation on package statement", 1, findMatchesCount(source4, "@'_Annotation", true));
}
public void testBoxingAndUnboxing() {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 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.
@@ -171,7 +171,7 @@ public class TestCaseLoader {
public void loadTestCases(final Collection<String> classNamesIterator) {
for (String className : classNamesIterator) {
try {
Class candidateClass = Class.forName(className);
Class candidateClass = Class.forName(className, false, getClass().getClassLoader());
addClassIfTestCase(candidateClass);
}
catch (ClassNotFoundException e) {
@@ -26,6 +26,7 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
@@ -362,15 +363,15 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
if (myProject.isDisposed()) return;
TreeUtil.expandAll(myTree);
int listSelection = 0;
int scrollRow = -1;
int selectedListRow = 0;
int selectedTreeRow = -1;
if (myShowCheckboxes) {
if (myIncludedChanges.size() > 0) {
for (int i = 0; i < sortedChanges.size(); i++) {
T t = sortedChanges.get(i);
if (myIncludedChanges.contains(t)) {
listSelection = i;
selectedListRow = i;
break;
}
}
@@ -393,46 +394,32 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
@SuppressWarnings("unchecked")
final CheckboxTree.NodeState state = getNodeStatus(node);
if (state == CheckboxTree.NodeState.FULL && node.isLeaf()) {
scrollRow = myTree.getRowForPath(new TreePath(node.getPath()));
selectedTreeRow = myTree.getRowForPath(new TreePath(node.getPath()));
break;
}
}
}
} else {
if (toSelect != null) {
ChangesBrowserNode root = (ChangesBrowserNode)model.getRoot();
final int[] rowToSelect = new int[] {-1};
TreeUtil.traverse(root, new TreeUtil.Traverse() {
@Override
public boolean accept(Object node) {
if (node instanceof DefaultMutableTreeNode) {
Object userObject = ((DefaultMutableTreeNode)node).getUserObject();
if (userObject instanceof Change) {
Change change = (Change)userObject;
VirtualFile virtualFile = change.getVirtualFile();
if ((virtualFile != null && virtualFile.equals(toSelect)) || seemsToBeMoved(change, toSelect)) {
TreeNode[] path = ((DefaultMutableTreeNode)node).getPath();
rowToSelect[0] = myTree.getRowForPath(new TreePath(path));
}
}
}
return rowToSelect[0] == -1;
}
});
scrollRow = rowToSelect[0] == -1 ? scrollRow : rowToSelect[0];
int rowInTree = findRowContainingFile((TreeNode)model.getRoot(), toSelect);
if (rowInTree > -1) {
selectedTreeRow = rowInTree;
}
int rowInList = findRowContainingFile(myList.getModel(), toSelect);
if (rowInList > -1) {
selectedListRow = rowInList;
}
}
}
if (changes.size() > 0) {
myList.setSelectedIndex(listSelection);
myList.ensureIndexIsVisible(listSelection);
myList.setSelectedIndex(selectedListRow);
myList.ensureIndexIsVisible(selectedListRow);
if (scrollRow >= 0) {
myTree.setSelectionRow(scrollRow);
if (selectedTreeRow >= 0) {
myTree.setSelectionRow(selectedTreeRow);
}
TreeUtil.showRowCentered(myTree, scrollRow, false);
TreeUtil.showRowCentered(myTree, selectedTreeRow, false);
}
}
};
@@ -443,6 +430,50 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
}
}
private static int findRowContainingFile(@NotNull ListModel listModel, @Nullable final VirtualFile toSelect) {
if (toSelect == null) {
return -1;
}
for (int i = 0; i < listModel.getSize(); i++) {
Object item = listModel.getElementAt(i);
if (item instanceof Change && matches((Change)item, toSelect)) {
return i;
}
}
return -1;
}
private int findRowContainingFile(@NotNull TreeNode root, @Nullable final VirtualFile toSelect) {
if (toSelect == null) {
return -1;
}
final Ref<Integer> row = Ref.create(-1);
TreeUtil.traverse(root, new TreeUtil.Traverse() {
@Override
public boolean accept(Object node) {
if (node instanceof DefaultMutableTreeNode) {
Object userObject = ((DefaultMutableTreeNode)node).getUserObject();
if (userObject instanceof Change) {
if (matches((Change)userObject, toSelect)) {
TreeNode[] path = ((DefaultMutableTreeNode)node).getPath();
row.set(myTree.getRowForPath(new TreePath(path)));
}
}
}
return row.get() == -1;
}
});
return row.get();
}
private static boolean matches(@NotNull Change change, @NotNull VirtualFile file) {
VirtualFile virtualFile = change.getVirtualFile();
return virtualFile != null && virtualFile.equals(file) || seemsToBeMoved(change, file);
}
private static boolean seemsToBeMoved(Change change, VirtualFile toSelect) {
ContentRevision afterRevision = change.getAfterRevision();
if (afterRevision == null) return false;
+1 -1
View File
@@ -155,7 +155,7 @@ public class GitVcs extends AbstractVcs<CommittedChangeList> {
myRollbackEnvironment = gitRollbackEnvironment;
myRevSelector = new GitRevisionSelector();
myConfigurable = new GitVcsConfigurable(myProject, gitProjectSettings, sharedSettings);
myUpdateEnvironment = new GitUpdateEnvironment(myProject, this, gitProjectSettings);
myUpdateEnvironment = new GitUpdateEnvironment(myProject, gitProjectSettings);
myCommittedChangeListProvider = new GitCommittedChangeListProvider(myProject);
myOutgoingChangesProvider = new GitOutgoingChangesProvider(myProject);
myTreeDiffProvider = new GitTreeDiffProvider(myProject);
@@ -52,6 +52,7 @@ import git4idea.repo.GitRepositoryManager;
import git4idea.update.GitRebaseOverMergeProblem;
import git4idea.update.GitUpdateProcess;
import git4idea.update.GitUpdateResult;
import git4idea.update.GitUpdater;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -383,7 +384,8 @@ public class GitPushOperation {
private void savePushUpdateSettings(@NotNull PushUpdateSettings settings, boolean rebaseOverMergeDetected) {
UpdateMethod updateMethod = settings.getUpdateMethod();
mySettings.setUpdateAllRootsIfPushRejected(settings.shouldUpdateAllRoots());
if (!rebaseOverMergeDetected) { // don't overwrite explicit "rebase" with temporary "merge" caused by merge commits
if (!rebaseOverMergeDetected // don't overwrite explicit "rebase" with temporary "merge" caused by merge commits
&& mySettings.getUpdateType() != updateMethod && mySettings.getUpdateType() != UpdateMethod.BRANCH_DEFAULT) { // don't overwrite "branch default" setting
mySettings.setUpdateType(updateMethod);
}
}
@@ -392,6 +394,10 @@ public class GitPushOperation {
private PushUpdateSettings readPushUpdateSettings() {
boolean updateAllRoots = mySettings.shouldUpdateAllRootsIfPushRejected();
UpdateMethod updateMethod = mySettings.getUpdateType();
if (updateMethod == UpdateMethod.BRANCH_DEFAULT) {
// deliberate limitation: we have only 2 buttons => choose method from the 1st repo if different
updateMethod = GitUpdater.resolveUpdateMethod(myProject, myPushSpecs.keySet().iterator().next().getRoot());
}
return new PushUpdateSettings(updateAllRoots, updateMethod);
}
@@ -429,12 +435,9 @@ public class GitPushOperation {
protected GitUpdateResult update(@NotNull Collection<GitRepository> rootsToUpdate,
@NotNull UpdateMethod updateMethod,
boolean checkForRebaseOverMergeProblem) {
GitUpdateProcess.UpdateMethod um = updateMethod == UpdateMethod.MERGE ?
GitUpdateProcess.UpdateMethod.MERGE :
GitUpdateProcess.UpdateMethod.REBASE;
GitUpdateResult updateResult = new GitUpdateProcess(myProject, myPlatformFacade, myProgressIndicator,
new HashSet<GitRepository>(rootsToUpdate), UpdatedFiles.create(),
checkForRebaseOverMergeProblem).update(um);
checkForRebaseOverMergeProblem).update(updateMethod);
for (GitRepository repository : rootsToUpdate) {
repository.getRoot().refresh(true, true);
repository.update();
@@ -220,6 +220,12 @@ class GitRejectedPushUpdateDialog extends DialogWrapper {
return myRebaseOverMergeProblemDetected;
}
@TestOnly
@NotNull
Action getDefaultAction() {
return Boolean.TRUE.equals(myMergeAction.getValue(DEFAULT_ACTION)) ? myMergeAction : myRebaseAction;
}
private class MergeAction extends AbstractAction {
MergeAction() {
super("&Merge");
@@ -16,7 +16,6 @@
package git4idea.update;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -29,7 +28,6 @@ import com.intellij.openapi.vcs.update.UpdateSession;
import com.intellij.openapi.vcs.update.UpdatedFiles;
import com.intellij.openapi.vfs.VirtualFile;
import git4idea.GitPlatformFacade;
import git4idea.GitVcs;
import git4idea.config.GitVcsSettings;
import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
@@ -41,21 +39,12 @@ import java.util.Set;
import static git4idea.GitUtil.*;
/**
* Git update environment implementation. The environment does
* {@code git pull -v} for each vcs root. Rebase variant is detected
* and processed as well.
*/
public class GitUpdateEnvironment implements UpdateEnvironment {
private final GitVcs myVcs;
private final Project myProject;
private final GitVcsSettings mySettings;
@NotNull private final GitPlatformFacade myPlatformFacade;
private static final Logger LOG = Logger.getInstance(GitUpdateEnvironment.class);
public GitUpdateEnvironment(@NotNull Project project, @NotNull GitVcs vcs, GitVcsSettings settings) {
myVcs = vcs;
public GitUpdateEnvironment(@NotNull Project project, @NotNull GitVcsSettings settings) {
myProject = project;
mySettings = settings;
myPlatformFacade = ServiceManager.getService(project, GitPlatformFacade.class);
@@ -72,7 +61,7 @@ public class GitUpdateEnvironment implements UpdateEnvironment {
final GitUpdateProcess gitUpdateProcess = new GitUpdateProcess(myProject, myPlatformFacade,
progressIndicator, getRepositoriesFromRoots(repositoryManager, roots),
updatedFiles, true);
boolean result = gitUpdateProcess.update(GitUpdateProcess.UpdateMethod.READ_FROM_SETTINGS).isSuccess();
boolean result = gitUpdateProcess.update(mySettings.getUpdateType()).isSuccess();
return new GitUpdateSession(result);
}
@@ -45,6 +45,7 @@ import git4idea.GitUtil;
import git4idea.branch.GitBranchPair;
import git4idea.branch.GitBranchUtil;
import git4idea.commands.Git;
import git4idea.config.UpdateMethod;
import git4idea.merge.GitConflictResolver;
import git4idea.merge.GitMergeCommittingConflictResolver;
import git4idea.merge.GitMerger;
@@ -83,12 +84,6 @@ public class GitUpdateProcess {
private GitUpdateResult myResult;
private final Collection<VirtualFile> myRootsToSave;
public enum UpdateMethod {
MERGE,
REBASE,
READ_FROM_SETTINGS
}
public GitUpdateProcess(@NotNull Project project,
@NotNull GitPlatformFacade platformFacade,
@Nullable ProgressIndicator progressIndicator,
@@ -298,15 +293,8 @@ public class GitUpdateProcess {
LOG.info("updateImpl: defining updaters...");
for (GitRepository repository : myRepositories) {
VirtualFile root = repository.getRoot();
final GitUpdater updater;
if (updateMethod == UpdateMethod.MERGE) {
updater = new GitMergeUpdater(myProject, myGit, root, myTrackedBranches, myProgressIndicator, myUpdatedFiles);
} else if (updateMethod == UpdateMethod.REBASE) {
updater = new GitRebaseUpdater(myProject, myGit, root, myTrackedBranches, myProgressIndicator, myUpdatedFiles);
} else {
updater = GitUpdater.getUpdater(myProject, myGit, myTrackedBranches, root, myProgressIndicator, myUpdatedFiles);
}
GitUpdater updater = GitUpdater.getUpdater(myProject, myGit, myTrackedBranches, root, myProgressIndicator, myUpdatedFiles,
updateMethod);
if (updater.isUpdateNeeded()) {
updaters.put(root, updater);
}
@@ -29,7 +29,7 @@ import git4idea.commands.Git;
import git4idea.commands.GitCommand;
import git4idea.commands.GitSimpleHandler;
import git4idea.config.GitConfigUtil;
import git4idea.config.GitVcsSettings;
import git4idea.config.UpdateMethod;
import git4idea.merge.MergeChangeCollector;
import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
@@ -76,43 +76,35 @@ public abstract class GitUpdater {
* @return {@link GitMergeUpdater} or {@link GitRebaseUpdater}.
*/
@NotNull
public static GitUpdater getUpdater(@NotNull Project project, @NotNull Git git, @NotNull Map<VirtualFile, GitBranchPair> trackedBranches,
@NotNull VirtualFile root, @NotNull ProgressIndicator progressIndicator,
@NotNull UpdatedFiles updatedFiles) {
final GitVcsSettings settings = GitVcsSettings.getInstance(project);
if (settings == null) {
return getDefaultUpdaterForBranch(project, git, root, trackedBranches, progressIndicator, updatedFiles);
public static GitUpdater getUpdater(@NotNull Project project,
@NotNull Git git,
@NotNull Map<VirtualFile, GitBranchPair> trackedBranches,
@NotNull VirtualFile root,
@NotNull ProgressIndicator progressIndicator,
@NotNull UpdatedFiles updatedFiles,
@NotNull UpdateMethod updateMethod) {
if (updateMethod == UpdateMethod.BRANCH_DEFAULT) {
updateMethod = resolveUpdateMethod(project, root);
}
switch (settings.getUpdateType()) {
case REBASE:
return new GitRebaseUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles);
case MERGE:
return new GitMergeUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles);
case BRANCH_DEFAULT:
// use default for the branch
return getDefaultUpdaterForBranch(project, git, root, trackedBranches, progressIndicator, updatedFiles);
}
return getDefaultUpdaterForBranch(project, git, root, trackedBranches, progressIndicator, updatedFiles);
return updateMethod == UpdateMethod.REBASE ?
new GitRebaseUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles):
new GitMergeUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles);
}
@NotNull
private static GitUpdater getDefaultUpdaterForBranch(@NotNull Project project, @NotNull Git git, @NotNull VirtualFile root,
@NotNull Map<VirtualFile, GitBranchPair> trackedBranches,
@NotNull ProgressIndicator progressIndicator, @NotNull UpdatedFiles updatedFiles) {
try {
GitLocalBranch branch = GitBranchUtil.getCurrentBranch(project, root);
boolean rebase = false;
if (branch != null) {
public static UpdateMethod resolveUpdateMethod(@NotNull Project project, @NotNull VirtualFile root) {
GitLocalBranch branch = GitBranchUtil.getCurrentBranch(project, root);
boolean rebase = false;
if (branch != null) {
try {
String rebaseValue = GitConfigUtil.getValue(project, root, "branch." + branch.getName() + ".rebase");
rebase = rebaseValue != null && rebaseValue.equalsIgnoreCase("true");
}
if (rebase) {
return new GitRebaseUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles);
catch (VcsException e) {
LOG.warn("Couldn't get git config branch." + branch.getName() + ".rebase", e);
}
} catch (VcsException e) {
LOG.info("getDefaultUpdaterForBranch branch", e);
}
return new GitMergeUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles);
return rebase ? UpdateMethod.REBASE : UpdateMethod.MERGE;
}
@NotNull
@@ -18,7 +18,6 @@ package git4idea.push;
import com.intellij.dvcs.push.PushSpec;
import com.intellij.dvcs.push.PushSupport;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.vcs.AbstractVcsHelper;
@@ -148,9 +147,9 @@ abstract class GitPushOperationBaseTest extends GitPlatformTest {
}
protected void agreeToUpdate(final int exitCode) {
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler() {
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@Override
public int handleDialog(DialogWrapper dialog) {
public int handleDialog(GitRejectedPushUpdateDialog dialog) {
return exitCode;
}
});
@@ -18,6 +18,7 @@ package git4idea.push;
import com.intellij.dvcs.push.PushSpec;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.util.io.FileUtil;
@@ -36,6 +37,7 @@ import git4idea.update.GitUpdateResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
@@ -47,6 +49,7 @@ import static git4idea.test.GitExecutor.*;
import static git4idea.test.GitTestUtil.makeCommit;
import static java.util.Collections.singletonMap;
@SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale")
public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
protected GitRepository myRepository;
@@ -121,9 +124,9 @@ public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
pushCommitFromBro();
final Ref<Boolean> dialogShown = Ref.create(false);
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler() {
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@Override
public int handleDialog(DialogWrapper dialog) {
public int handleDialog(GitRejectedPushUpdateDialog dialog) {
dialogShown.set(true);
return DialogWrapper.CANCEL_EXIT_CODE;
}
@@ -141,9 +144,9 @@ public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
git("checkout -b feature");
final Ref<Boolean> dialogShown = Ref.create(false);
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler() {
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@Override
public int handleDialog(DialogWrapper dialog) {
public int handleDialog(GitRejectedPushUpdateDialog dialog) {
dialogShown.set(true);
return DialogWrapper.CANCEL_EXIT_CODE;
}
@@ -188,6 +191,50 @@ public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
assertFalse("The commit shouldn't be pushed", history.contains(hash));
}
public void test_use_selected_update_method_for_all_consecutive_updates() throws IOException {
pushCommitFromBro();
cd(myRepository);
makeCommit("afile.txt");
agreeToUpdate(GitRejectedPushUpdateDialog.REBASE_EXIT_CODE);
refresh();
PushSpec<GitPushSource, GitPushTarget> pushSpec = makePushSpec(myRepository, "master", "origin/master");
GitPushResult result = new GitPushOperation(myProject, myPushSupport, singletonMap(myRepository, pushSpec), null, false) {
boolean updateHappened;
@NotNull
@Override
protected GitUpdateResult update(@NotNull Collection<GitRepository> rootsToUpdate,
@NotNull UpdateMethod updateMethod,
boolean checkForRebaseOverMergeProblem) {
GitUpdateResult updateResult = super.update(rootsToUpdate, updateMethod, checkForRebaseOverMergeProblem);
try {
if (!updateHappened) {
updateHappened = true;
pushCommitFromBro();
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
return updateResult;
}
}.execute();
assertResult(SUCCESS, 1, "master", "origin/master", GitUpdateResult.SUCCESS, result.getResults().get(myRepository));
cd(myRepository);
String[] commitMessages = StringUtil.splitByLines(log("--pretty=%s"));
boolean mergeCommitsInTheLog = ContainerUtil.exists(commitMessages, new Condition<String>() {
@Override
public boolean value(String s) {
return s.toLowerCase().contains("merge");
}
});
assertFalse("Unexpected merge commits when rebase method is selected", mergeCommitsInTheLog);
}
public void test_force_push() throws IOException {
String lostHash = pushCommitFromBro();
cd(myRepository);
@@ -305,6 +352,64 @@ public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
UpdateMethod.REBASE, myGitSettings.getUpdateType());
}
public void test_respect_branch_default_setting_for_rejected_push_dialog() throws IOException {
generateUpdateNeeded();
myGitSettings.setUpdateType(UpdateMethod.BRANCH_DEFAULT);
git("config branch.master.rebase true");
final Ref<String> defaultActionName = Ref.create();
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@Override
public int handleDialog(@NotNull GitRejectedPushUpdateDialog dialog) {
defaultActionName.set((String)dialog.getDefaultAction().getValue(Action.NAME));
return DialogWrapper.CANCEL_EXIT_CODE;
}
});
push("master", "origin/master");
assertTrue("Default action in rejected-push dialog is incorrect: " + defaultActionName.get(),
defaultActionName.get().toLowerCase().contains("rebase"));
git("config branch.master.rebase false");
push("master", "origin/master");
assertTrue("Default action in rejected-push dialog is incorrect: " + defaultActionName.get(),
defaultActionName.get().toLowerCase().contains("merge"));
}
public void test_respect_branch_default_setting_for_silent_update_when_rejected_push() throws IOException {
generateUpdateNeeded();
myGitSettings.setUpdateType(UpdateMethod.BRANCH_DEFAULT);
git("config branch.master.rebase true");
myGitSettings.setAutoUpdateIfPushRejected(true);
push("master", "origin/master");
assertFalse("Unexpected merge commit: rebase should have happened", log("-1 --pretty=%s").toLowerCase().startsWith("merge"));
}
// there is no "branch default" choice in the rejected push dialog
// => simply don't rewrite the setting if the same value is chosen, as was default value initially
public void test_dont_overwrite_branch_default_setting_when_agree_in_rejected_push_dialog() throws IOException {
generateUpdateNeeded();
myGitSettings.setUpdateType(UpdateMethod.BRANCH_DEFAULT);
git("config branch.master.rebase true");
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@Override
public int handleDialog(@NotNull GitRejectedPushUpdateDialog dialog) {
return GitRejectedPushUpdateDialog.REBASE_EXIT_CODE;
}
});
push("master", "origin/master");
assertEquals(UpdateMethod.BRANCH_DEFAULT, myGitSettings.getUpdateType());
}
private void generateUpdateNeeded() throws IOException {
pushCommitFromBro();
cd(myRepository);
makeCommit("file.txt");
}
private void generateUnpushedMergedCommitProblem() throws IOException {
pushCommitFromBro();
cd(myRepository);
@@ -48,8 +48,15 @@ public class TestDialogManager extends DialogManager {
@Override
protected void showDialog(@NotNull DialogWrapper dialog) {
TestDialogHandler handler = myHandlers.get(dialog.getClass());
int exitCode = handler != null ? handler.handleDialog(dialog) : DialogWrapper.OK_EXIT_CODE;
dialog.close(exitCode, exitCode == DialogWrapper.OK_EXIT_CODE);
int exitCode = DialogWrapper.OK_EXIT_CODE;
try {
if (handler != null) {
exitCode = handler.handleDialog(dialog);
}
}
finally {
dialog.close(exitCode, exitCode == DialogWrapper.OK_EXIT_CODE);
}
}
@Override