All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.server.computation.duplication.Duplication Maven / Gradle / Ivy

There is a newer version: 7.2.1
Show newest version
/*
 * SonarQube
 * Copyright (C) 2009-2016 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.server.computation.duplication;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Ordering;
import java.util.Comparator;
import java.util.Objects;
import java.util.SortedSet;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.FluentIterable.from;
import static java.util.Objects.requireNonNull;

@Immutable
public final class Duplication {
  private static final Ordering DUPLICATE_ORDERING = Ordering.from(DuplicateComparatorByType.INSTANCE)
    .compound(Ordering.natural().onResultOf(DuplicateToFileKey.INSTANCE))
    .compound(Ordering.natural().onResultOf(DuplicateToTextBlock.INSTANCE));

  private final TextBlock original;
  private final SortedSet duplicates;

  /**
   * @throws NullPointerException if {@code original} is {@code null} or {@code duplicates} is {@code null} or {@code duplicates} contains {@code null}
   * @throws IllegalArgumentException if {@code duplicates} is empty
   * @throws IllegalArgumentException if {@code duplicates} contains a {@link InnerDuplicate} with {@code original}
   */
  public Duplication(final TextBlock original, final Iterable duplicates) {
    this.original = requireNonNull(original, "original TextBlock can not be null");
    this.duplicates = from(requireNonNull(duplicates, "duplicates can not be null"))
      .filter(FailOnNullDuplicate.INSTANCE)
      .filter(new EnsureInnerDuplicateIsNotOriginalTextBlock(original))
      .toSortedSet(DUPLICATE_ORDERING);
    checkArgument(!this.duplicates.isEmpty(), "duplicates can not be empty");
  }

  /**
   * The duplicated block.
   */
  public TextBlock getOriginal() {
    return this.original;
  }

  /**
   * The duplicates of the original, sorted by inner duplicates, then project duplicates, then cross-project duplicates.
   * For each category of duplicate, they are sorted by:
   * 
    *
  • file key (unless it's an InnerDuplicate)
  • *
  • then by TextBlocks by start line and in case of same line, by shortest first
  • *
The returned set can not be empty and no inner duplicate can contain the original {@link TextBlock}.

*/ public SortedSet getDuplicates() { return this.duplicates; } @Override public boolean equals(@Nullable Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Duplication that = (Duplication) o; return original.equals(that.original) && duplicates.equals(that.duplicates); } @Override public int hashCode() { return Objects.hash(original, duplicates); } @Override public String toString() { return "Duplication{" + "original=" + original + ", duplicates=" + duplicates + '}'; } private enum FailOnNullDuplicate implements Predicate { INSTANCE; @Override public boolean apply(@Nullable Duplicate input) { requireNonNull(input, "duplicates can not contain null"); return true; } } private enum DuplicateComparatorByType implements Comparator { INSTANCE; @Override public int compare(Duplicate o1, Duplicate o2) { return toIndexType(o1) - toIndexType(o2); } private static int toIndexType(Duplicate duplicate) { if (duplicate instanceof InnerDuplicate) { return 0; } if (duplicate instanceof InProjectDuplicate) { return 1; } if (duplicate instanceof CrossProjectDuplicate) { return 2; } throw new IllegalArgumentException("Unsupported type of Duplicate " + duplicate.getClass().getName()); } } private enum DuplicateToTextBlock implements Function { INSTANCE; @Override @Nonnull public TextBlock apply(@Nonnull Duplicate input) { return input.getTextBlock(); } } private static class EnsureInnerDuplicateIsNotOriginalTextBlock implements Predicate { private final TextBlock original; public EnsureInnerDuplicateIsNotOriginalTextBlock(TextBlock original) { this.original = original; } @Override public boolean apply(@Nullable Duplicate input) { if (input instanceof InnerDuplicate) { checkArgument(!original.equals(input.getTextBlock()), "TextBlock of an InnerDuplicate can not be the original TextBlock"); } return true; } } private enum DuplicateToFileKey implements Function { INSTANCE; @Override @Nonnull public String apply(@Nonnull Duplicate duplicate) { if (duplicate instanceof InnerDuplicate) { return ""; } if (duplicate instanceof InProjectDuplicate) { return ((InProjectDuplicate) duplicate).getFile().getKey(); } if (duplicate instanceof CrossProjectDuplicate) { return ((CrossProjectDuplicate) duplicate).getFileKey(); } throw new IllegalArgumentException("Unsupported type of Duplicate " + duplicate.getClass().getName()); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy