/** * Running time - O(N*2*C), where N - number of clones, which was found earlier and C - time of {@link #containsIn(CloneGroup, CloneGroup)}. */ public void add(CloneGroup current) { Iterator<CloneGroup> i = filtered.iterator(); while (i.hasNext()) { CloneGroup earlier = i.next(); // Note that following two conditions cannot be true together - proof by contradiction: // let C be the current clone and A and B were found earlier // then since relation is transitive - (A in C) and (C in B) => (A in B) // so A should be filtered earlier if (Filter.containsIn(current, earlier)) { // current clone fully covered by clone, which was found earlier return; } if (Filter.containsIn(earlier, current)) { // current clone fully covers clone, which was found earlier i.remove(); } } filtered.add(current); }
private void reportClones(BlocksGroup beginGroup, BlocksGroup endGroup, int cloneLength) { List<Block[]> pairs = beginGroup.pairs(endGroup, cloneLength); ClonePart origin = null; List<ClonePart> parts = new ArrayList<>(); for (int i = 0; i < pairs.size(); i++) { Block[] pair = pairs.get(i); Block firstBlock = pair[0]; Block lastBlock = pair[1]; ClonePart part = new ClonePart(firstBlock.getResourceId(), firstBlock.getIndexInFile(), firstBlock.getStartLine(), lastBlock.getEndLine()); if (originResourceId.equals(part.getResourceId())) { if (origin == null || part.getUnitStart() < origin.getUnitStart()) { origin = part; } } parts.add(part); } filter.add(CloneGroup.builder().setLength(cloneLength).setOrigin(origin).setParts(parts).build()); }
/** * Performs detection and returns list of clone groups between file (which represented as a collection of blocks) and index. * Note that this method ignores blocks for this file, that will be retrieved from index. */ public static List<CloneGroup> detect(CloneIndex cloneIndex, Collection<Block> fileBlocks) { if (fileBlocks.isEmpty()) { return Collections.emptyList(); } OriginalCloneDetectionAlgorithm reporter = new OriginalCloneDetectionAlgorithm(cloneIndex); reporter.findClones(fileBlocks); return reporter.filter.getResult(); } }
/** * Given: * <pre> * c1: a[1-1] * c2: a[1-1] * </pre> * Expected: * reflexive - c1 in c1, * antisymmetric - c1 in c2, c2 in c1, because c1 = c2 */ @Test public void reflexive_and_antisymmetric() { CloneGroup c1 = newCloneGroup(1, newClonePart("a", 1)); CloneGroup c2 = newCloneGroup(1, newClonePart("a", 1)); assertThat(Filter.containsIn(c1, c1), is(true)); assertThat(Filter.containsIn(c1, c2), is(true)); assertThat(Filter.containsIn(c2, c1), is(true)); }
/** * Performs detection and returns list of clone groups between file (which represented as a collection of blocks) and index. * Note that this method ignores blocks for this file, that will be retrieved from index. */ public static List<CloneGroup> detect(CloneIndex cloneIndex, Collection<Block> fileBlocks) { if (fileBlocks.isEmpty()) { return Collections.EMPTY_LIST; } OriginalCloneDetectionAlgorithm reporter = new OriginalCloneDetectionAlgorithm(cloneIndex); reporter.findClones(fileBlocks); return reporter.filter.getResult(); }
private void reportClones(BlocksGroup beginGroup, BlocksGroup endGroup, int cloneLength) { List<Block[]> pairs = beginGroup.pairs(endGroup, cloneLength); ClonePart origin = null; List<ClonePart> parts = Lists.newArrayList(); for (int i = 0; i < pairs.size(); i++) { Block[] pair = pairs.get(i); Block firstBlock = pair[0]; Block lastBlock = pair[1]; ClonePart part = new ClonePart(firstBlock.getResourceId(), firstBlock.getIndexInFile(), firstBlock.getStartLine(), lastBlock.getEndLine()); if (originResourceId.equals(part.getResourceId())) { if (origin == null) { origin = part; } else if (part.getUnitStart() < origin.getUnitStart()) { origin = part; } } parts.add(part); } filter.add(CloneGroup.builder().setLength(cloneLength).setOrigin(origin).setParts(parts).build()); }
/** * Given: * <pre> * c1: a[0-2] * c2: a[0-0] * </pre> * Expected: * <pre> * c1 not in c2 * </pre> */ @Test public void length_of_C1_bigger_than_length_of_C2() { CloneGroup c1 = spy(newCloneGroup(3, newClonePart("a", 0))); CloneGroup c2 = spy(newCloneGroup(1, newClonePart("a", 0))); assertThat(Filter.containsIn(c1, c2), is(false)); // containsIn method should check only origin and length - no need to compare all parts verify(c1).getCloneUnitLength(); verify(c2).getCloneUnitLength(); verifyNoMoreInteractions(c1); verifyNoMoreInteractions(c2); }
/** * Given: * <pre> * c1: a[2-2] * c2: a[0-1], a[2-3] * </pre> * Expected: * <pre> * c1 in c2 * c2 not in c1 * </pre> */ @Test public void second_part_of_C2_covers_first_part_of_C1() { CloneGroup c1 = newCloneGroup(1, newClonePart("a", 2)); CloneGroup c2 = newCloneGroup(2, newClonePart("a", 0), newClonePart("a", 2)); assertThat(Filter.containsIn(c1, c2), is(true)); assertThat(Filter.containsIn(c2, c1), is(false)); }
/** * Given: * <pre> * c1: a[0-0], a[2-2] * c2: a[0-2], b[0-2] * </pre> * Expected: * <pre> * c1 not in c2 (all parts of c1 covered by parts of c2, but different resources) * c2 not in c1 (not all parts of c2 covered by parts of c1 and different resources) * </pre> */ @Test public void different_resources() { CloneGroup c1 = newCloneGroup(1, newClonePart("a", 0), newClonePart("a", 2)); CloneGroup c2 = newCloneGroup(3, newClonePart("a", 0), newClonePart("b", 0)); assertThat(Filter.containsIn(c1, c2), is(false)); assertThat(Filter.containsIn(c2, c1), is(false)); }
/** * Given: * <pre> * c1: a[1-1] * c2: a[2-2] * </pre> * Expected: c1 not in c2, c2 not in c1 */ @Test public void start_index_in_C1_less_than_in_C2() { CloneGroup c1 = newCloneGroup(1, newClonePart("a", 1)); CloneGroup c2 = newCloneGroup(1, newClonePart("a", 2)); assertThat(Filter.containsIn(c1, c2), is(false)); }
/** * Given: * <pre> * c1: a[0-0], a[2-2], b[0-0], b[2-2] * c2: a[0-2], b[0-2] * </pre> * Expected: * <pre> * c1 in c2 (all parts of c1 covered by parts of c2 and all resources the same) * c2 not in c1 (not all parts of c2 covered by parts of c1 and all resources the same) * </pre> */ @Test public void one_part_of_C2_covers_two_parts_of_C1() { // Note that line numbers don't matter for method which we test. CloneGroup c1 = newCloneGroup(1, newClonePart("a", 0), newClonePart("a", 2), newClonePart("b", 0), newClonePart("b", 2)); CloneGroup c2 = newCloneGroup(3, newClonePart("a", 0), newClonePart("b", 0)); assertThat(Filter.containsIn(c1, c2), is(true)); assertThat(Filter.containsIn(c2, c1), is(false)); }
/** * Running time - O(N*2*C), where N - number of clones, which was found earlier and C - time of {@link #containsIn(CloneGroup, CloneGroup)}. */ public void add(CloneGroup current) { Iterator<CloneGroup> i = filtered.iterator(); while (i.hasNext()) { CloneGroup earlier = i.next(); // Note that following two conditions cannot be true together - proof by contradiction: // let C be the current clone and A and B were found earlier // then since relation is transitive - (A in C) and (C in B) => (A in B) // so A should be filtered earlier if (Filter.containsIn(current, earlier)) { // current clone fully covered by clone, which was found earlier return; } if (Filter.containsIn(earlier, current)) { // current clone fully covers clone, which was found earlier i.remove(); } } filtered.add(current); }