View Javadoc
1   /*
2    * Copyright (C) 2009, Christian Halstrick <christian.halstrick@sap.com> and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  
11  package org.eclipse.jgit.merge;
12  
13  import java.util.Iterator;
14  import java.util.List;
15  
16  import org.eclipse.jgit.diff.Sequence;
17  import org.eclipse.jgit.merge.MergeChunk.ConflictState;
18  import org.eclipse.jgit.util.IntList;
19  
20  /**
21   * The result of merging a number of {@link org.eclipse.jgit.diff.Sequence}
22   * objects. These sequences have one common predecessor sequence. The result of
23   * a merge is a list of MergeChunks. Each MergeChunk contains either a range (a
24   * subsequence) from one of the merged sequences, a range from the common
25   * predecessor or a conflicting range from one of the merged sequences. A
26   * conflict will be reported as multiple chunks, one for each conflicting range.
27   * The first chunk for a conflict is marked specially to distinguish the border
28   * between two consecutive conflicts.
29   * <p>
30   * This class does not know anything about how to present the merge result to
31   * the end-user. MergeFormatters have to be used to construct something human
32   * readable.
33   *
34   * @param <S>
35   *            type of sequence.
36   */
37  public class MergeResult<S extends Sequence> implements Iterable<MergeChunk> {
38  	private final List<S> sequences;
39  
40  	final IntList chunks = new IntList();
41  
42  	private boolean containsConflicts = false;
43  
44  	/**
45  	 * Creates a new empty MergeResult
46  	 *
47  	 * @param sequences
48  	 *            contains the common predecessor sequence at position 0
49  	 *            followed by the merged sequences. This list should not be
50  	 *            modified anymore during the lifetime of this
51  	 *            {@link org.eclipse.jgit.merge.MergeResult}.
52  	 */
53  	public MergeResult(List<S> sequences) {
54  		this.sequences = sequences;
55  	}
56  
57  	/**
58  	 * Adds a new range from one of the merged sequences or from the common
59  	 * predecessor. This method can add conflicting and non-conflicting ranges
60  	 * controlled by the conflictState parameter
61  	 *
62  	 * @param srcIdx
63  	 *            determines from which sequence this range comes. An index of
64  	 *            x specifies the x+1 element in the list of sequences
65  	 *            specified to the constructor
66  	 * @param begin
67  	 *            the first element from the specified sequence which should be
68  	 *            included in the merge result. Indexes start with 0.
69  	 * @param end
70  	 *            specifies the end of the range to be added. The element this
71  	 *            index points to is the first element which not added to the
72  	 *            merge result. All elements between begin (including begin) and
73  	 *            this element are added.
74  	 * @param conflictState
75  	 *            when set to NO_CONLICT a non-conflicting range is added.
76  	 *            This will end implicitly all open conflicts added before.
77  	 */
78  	public void add(int srcIdx, int begin, int end, ConflictState conflictState) {
79  		chunks.add(conflictState.ordinal());
80  		chunks.add(srcIdx);
81  		chunks.add(begin);
82  		chunks.add(end);
83  		if (conflictState != ConflictState.NO_CONFLICT)
84  			containsConflicts = true;
85  	}
86  
87  	/**
88  	 * Returns the common predecessor sequence and the merged sequence in one
89  	 * list. The common predecessor is the first element in the list
90  	 *
91  	 * @return the common predecessor at position 0 followed by the merged
92  	 *         sequences.
93  	 */
94  	public List<S> getSequences() {
95  		return sequences;
96  	}
97  
98  	static final ConflictState[] states = ConflictState.values();
99  
100 	/** {@inheritDoc} */
101 	@Override
102 	public Iterator<MergeChunk> iterator() {
103 		return new Iterator<MergeChunk>() {
104 			int idx;
105 
106 			@Override
107 			public boolean hasNext() {
108 				return (idx < chunks.size());
109 			}
110 
111 			@Override
112 			public MergeChunk next() {
113 				ConflictState state = states[chunks.get(idx++)];
114 				int srcIdx = chunks.get(idx++);
115 				int begin = chunks.get(idx++);
116 				int end = chunks.get(idx++);
117 				return new MergeChunk(srcIdx, begin, end, state);
118 			}
119 
120 			@Override
121 			public void remove() {
122 				throw new UnsupportedOperationException();
123 			}
124 		};
125 	}
126 
127 	/**
128 	 * Whether this merge result contains conflicts
129 	 *
130 	 * @return true if this merge result contains conflicts
131 	 */
132 	public boolean containsConflicts() {
133 		return containsConflicts;
134 	}
135 
136 	/**
137 	 * Sets explicitly whether this merge should be seen as containing a
138 	 * conflict or not. Needed because during RecursiveMerger we want to do
139 	 * content-merges and take the resulting content (even with conflict
140 	 * markers!) as new conflict-free content
141 	 *
142 	 * @param containsConflicts
143 	 *            whether this merge should be seen as containing a conflict or
144 	 *            not.
145 	 * @since 3.5
146 	 */
147 	protected void setContainsConflicts(boolean containsConflicts) {
148 		this.containsConflicts = containsConflicts;
149 	}
150 }