@@ -21,4 +21,8 @@ package org.sonar.server.computation.component; | |||
public interface ComponentVisitor { | |||
void visit(Component tree); | |||
enum Order { | |||
PRE_ORDER, POST_ORDER | |||
} | |||
} |
@@ -53,7 +53,7 @@ public abstract class DepthTraversalTypeAwareVisitor implements TypeAwareVisitor | |||
} | |||
} | |||
protected void visitNode(Component component) { | |||
private void visitNode(Component component) { | |||
visitAny(component); | |||
switch (component.getType()) { | |||
case PROJECT: | |||
@@ -110,8 +110,4 @@ public abstract class DepthTraversalTypeAwareVisitor implements TypeAwareVisitor | |||
public void visitAny(Component component) { | |||
// empty implementation, meant to be override at will by subclasses | |||
} | |||
public enum Order { | |||
PRE_ORDER, POST_ORDER | |||
} | |||
} |
@@ -0,0 +1,295 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.component; | |||
import java.util.ArrayDeque; | |||
import java.util.Deque; | |||
import java.util.Iterator; | |||
import java.util.NoSuchElementException; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | |||
/** | |||
* A ComponentVisitor which provide access to a representation of the path from the root to the currently visited | |||
* Component. It also provides a way to have an object associated to each Component and access it and all of its | |||
* parent's. | |||
* As for {@link DepthTraversalTypeAwareVisitor}, this visitor supports max depth visit and ordering. | |||
*/ | |||
public abstract class PathAwareVisitor<T> implements ComponentVisitor { | |||
private final Component.Type maxDepth; | |||
private final Order order; | |||
private final StackElementFactory<T> factory; | |||
private final DequeBasedPath<T> stack = new DequeBasedPath<>(); | |||
public PathAwareVisitor(Component.Type maxDepth, Order order, StackElementFactory<T> factory) { | |||
this.maxDepth = requireNonNull(maxDepth); | |||
this.order = requireNonNull(order); | |||
this.factory = requireNonNull(factory, "Factory can not be null"); | |||
} | |||
@Override | |||
public void visit(Component component) { | |||
if (component.getType().isDeeperThan(maxDepth)) { | |||
return; | |||
} | |||
stack.add(new PathElementImpl<>(component, createForComponent(component))); | |||
if (order == PRE_ORDER) { | |||
visitNode(component); | |||
} | |||
visitChildren(component); | |||
if (order == POST_ORDER) { | |||
visitNode(component); | |||
} | |||
stack.pop(); | |||
} | |||
private T createForComponent(Component component) { | |||
switch (component.getType()) { | |||
case PROJECT: | |||
return factory.createForProject(component); | |||
case MODULE: | |||
return factory.createForModule(component); | |||
case DIRECTORY: | |||
return factory.createForDirectory(component); | |||
case FILE: | |||
return factory.createForFile(component); | |||
default: | |||
return factory.createForUnknown(component); | |||
} | |||
} | |||
private void visitChildren(Component component) { | |||
if (component.getType() != maxDepth) { | |||
for (Component child : component.getChildren()) { | |||
visit(child); | |||
} | |||
} | |||
} | |||
private void visitNode(Component component) { | |||
visitAny(component, stack); | |||
switch (component.getType()) { | |||
case PROJECT: | |||
visitProject(component, stack); | |||
break; | |||
case MODULE: | |||
visitModule(component, stack); | |||
break; | |||
case DIRECTORY: | |||
visitDirectory(component, stack); | |||
break; | |||
case FILE: | |||
visitFile(component, stack); | |||
break; | |||
default: | |||
visitUnknown(component, stack); | |||
} | |||
} | |||
protected void visitProject(Component project, Path<T> path) { | |||
// empty implementation, meant to be override at will by subclasses | |||
} | |||
protected void visitModule(Component module, Path<T> path) { | |||
// empty implementation, meant to be override at will by subclasses | |||
} | |||
protected void visitDirectory(Component directory, Path<T> path) { | |||
// empty implementation, meant to be override at will by subclasses | |||
} | |||
protected void visitFile(Component file, Path<T> path) { | |||
// empty implementation, meant to be override at will by subclasses | |||
} | |||
protected void visitUnknown(Component unknownComponent, Path<T> path) { | |||
// empty implementation, meant to be override at will by subclasses | |||
} | |||
protected void visitAny(Component component, Path<T> path) { | |||
// empty implementation, meant to be override at will by subclasses | |||
} | |||
public interface StackElementFactory<T> { | |||
T createForProject(Component project); | |||
T createForModule(Component module); | |||
T createForDirectory(Component directory); | |||
T createForFile(Component file); | |||
T createForUnknown(Component file); | |||
} | |||
/** | |||
* A Simple implementation which uses the same factory method for all types which can be implemented by subclasses: | |||
* {@link #createForAny(Component)}. | |||
*/ | |||
public abstract static class SimpleStackElementFactory<T> implements StackElementFactory<T> { | |||
public abstract T createForAny(Component component); | |||
@Override | |||
public T createForProject(Component project) { | |||
return createForAny(project); | |||
} | |||
@Override | |||
public T createForModule(Component module) { | |||
return createForAny(module); | |||
} | |||
@Override | |||
public T createForDirectory(Component directory) { | |||
return createForAny(directory); | |||
} | |||
@Override | |||
public T createForFile(Component file) { | |||
return createForAny(file); | |||
} | |||
@Override | |||
public T createForUnknown(Component file) { | |||
return createForAny(file); | |||
} | |||
} | |||
private static class DequeBasedPath<T> implements Path<T>, Iterable<PathElement<T>> { | |||
private final Deque<PathElement<T>> deque = new ArrayDeque<>(); | |||
@Override | |||
public T current() { | |||
return deque.getFirst().getElement(); | |||
} | |||
@Override | |||
public T parent() { | |||
Iterator<PathElement<T>> iterator = deque.iterator(); | |||
if (iterator.hasNext()) { | |||
iterator.next(); | |||
if (iterator.hasNext()) { | |||
return iterator.next().getElement(); | |||
} | |||
} | |||
throw new NoSuchElementException("Path is either empty or has only one element. There is no parent"); | |||
} | |||
@Override | |||
public boolean isRoot() { | |||
return deque.size() == 1; | |||
} | |||
@Override | |||
public T root() { | |||
return deque.getLast().getElement(); | |||
} | |||
@Override | |||
public Iterator<PathElement<T>> iterator() { | |||
return deque.iterator(); | |||
} | |||
@Override | |||
public Iterable<PathElement<T>> getCurrentPath() { | |||
return this; | |||
} | |||
public void add(PathElement<T> pathElement) { | |||
deque.addFirst(pathElement); | |||
} | |||
public PathElement<T> pop() { | |||
return deque.pop(); | |||
} | |||
} | |||
public interface Path<T> { | |||
/** | |||
* The stacked element of the current Component. | |||
*/ | |||
T current(); | |||
/** | |||
* Tells whether the current Component is the root of the tree. | |||
*/ | |||
boolean isRoot(); | |||
/** | |||
* The stacked element of the parent of the current Component. | |||
* | |||
* @throws NoSuchElementException if the current Component is the root of the tree | |||
* @see #isRoot() | |||
*/ | |||
T parent(); | |||
/** | |||
* The stacked element of the root of the tree. | |||
*/ | |||
T root(); | |||
/** | |||
* The path to the current Component as an Iterable of {@link PathAwareVisitor.PathElement} which starts with | |||
* the {@link PathAwareVisitor.PathElement} of the current Component and ends with the | |||
* {@link PathAwareVisitor.PathElement} of the root of the tree. | |||
*/ | |||
Iterable<PathElement<T>> getCurrentPath(); | |||
} | |||
public interface PathElement<T> { | |||
/** | |||
* The Component on the path. | |||
*/ | |||
Component getComponent(); | |||
/** | |||
* The stacked element for the Component of this PathElement. | |||
*/ | |||
T getElement(); | |||
} | |||
private static final class PathElementImpl<T> implements PathElement<T> { | |||
private final Component component; | |||
private final T element; | |||
private PathElementImpl(Component component, T element) { | |||
this.component = component; | |||
this.element = element; | |||
} | |||
@Override | |||
public Component getComponent() { | |||
return component; | |||
} | |||
@Override | |||
public T getElement() { | |||
return element; | |||
} | |||
} | |||
} |
@@ -23,7 +23,7 @@ import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER; | |||
/** | |||
* Holds the reference to the root of the {@link Component} tree for the current CE run. |
@@ -69,7 +69,7 @@ import static org.sonar.api.measures.CoreMetrics.OPEN_ISSUES_KEY; | |||
import static org.sonar.api.measures.CoreMetrics.REOPENED_ISSUES_KEY; | |||
import static org.sonar.api.measures.CoreMetrics.VIOLATIONS_KEY; | |||
import static org.sonar.server.computation.component.Component.Type.FILE; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER; | |||
/** | |||
* Computes metrics related to number of issues. |
@@ -46,7 +46,7 @@ import org.sonar.server.computation.period.Period; | |||
import org.sonar.server.computation.period.PeriodsHolder; | |||
import org.sonar.server.db.DbClient; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | |||
/** | |||
* Set variations on all numeric measures found in the repository. |
@@ -36,7 +36,7 @@ import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor; | |||
import org.sonar.server.computation.component.TreeRootHolder; | |||
import org.sonar.server.db.DbClient; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | |||
/** | |||
* Persist duplications into |
@@ -49,7 +49,7 @@ import org.sonar.server.db.DbClient; | |||
import org.sonar.server.source.db.FileSourceDb; | |||
import org.sonar.server.util.CloseableIterator; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | |||
public class PersistFileSourcesStep implements ComputationStep { | |||
@@ -44,7 +44,7 @@ import org.sonar.server.computation.metric.MetricRepository; | |||
import org.sonar.server.db.DbClient; | |||
import static com.google.common.collect.FluentIterable.from; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | |||
public class PersistMeasuresStep implements ComputationStep { | |||
@@ -39,7 +39,7 @@ import org.sonar.server.db.DbClient; | |||
import org.sonar.server.source.index.SourceLineIndex; | |||
import static com.google.common.base.Objects.firstNonNull; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | |||
public class PersistNumberOfDaysSinceLastCommitStep implements ComputationStep { | |||
@@ -41,7 +41,7 @@ import org.sonar.server.computation.component.TreeRootHolder; | |||
import org.sonar.server.db.DbClient; | |||
import static com.google.common.collect.Sets.newHashSet; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | |||
/** | |||
* Persist project and module links |
@@ -34,7 +34,7 @@ import org.sonar.server.computation.qualitygate.QualityGate; | |||
import org.sonar.server.computation.qualitygate.QualityGateService; | |||
import static org.sonar.server.computation.component.Component.Type.PROJECT; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | |||
/** | |||
* This step retrieves the QualityGate for the current {@link ReportQueue.Item} and stores it in |
@@ -44,7 +44,7 @@ import org.sonar.server.computation.qualitygate.QualityGate; | |||
import org.sonar.server.computation.qualitygate.QualityGateHolder; | |||
import static org.sonar.server.computation.component.Component.Type.PROJECT; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | |||
/** | |||
* This step: |
@@ -42,7 +42,7 @@ import org.sonar.server.computation.metric.MetricRepository; | |||
import org.sonar.server.computation.qualityprofile.QPMeasureData; | |||
import org.sonar.server.computation.qualityprofile.QualityProfile; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER; | |||
public class QualityProfileEventsStep implements ComputationStep { | |||
private final TreeRootHolder treeRootHolder; |
@@ -29,7 +29,7 @@ import org.sonar.server.computation.component.Component; | |||
import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor; | |||
import org.sonar.server.computation.component.TreeRootHolder; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER; | |||
public class TreeRootHolderRule implements TestRule, TreeRootHolder { | |||
private Component root; |
@@ -0,0 +1,264 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.component; | |||
import com.google.common.base.Function; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.NoSuchElementException; | |||
import java.util.Objects; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nonnull; | |||
import javax.annotation.Nullable; | |||
import org.junit.Test; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static com.google.common.collect.FluentIterable.from; | |||
import static com.google.common.collect.ImmutableList.of; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.server.computation.component.Component.Type.DIRECTORY; | |||
import static org.sonar.server.computation.component.Component.Type.FILE; | |||
import static org.sonar.server.computation.component.Component.Type.MODULE; | |||
import static org.sonar.server.computation.component.Component.Type.PROJECT; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | |||
public class PathAwareVisitorTest { | |||
private static final int ROOT_REF = 1; | |||
private static final DumbComponent SOME_TREE_ROOT = DumbComponent.builder(PROJECT, ROOT_REF) | |||
.addChildren( | |||
DumbComponent.builder(MODULE, 11) | |||
.addChildren( | |||
DumbComponent.builder(DIRECTORY, 111) | |||
.addChildren( | |||
DumbComponent.builder(FILE, 1111).build(), | |||
DumbComponent.builder(FILE, 1112).build() | |||
) | |||
.build(), | |||
DumbComponent.builder(DIRECTORY, 112) | |||
.addChildren( | |||
DumbComponent.builder(FILE, 1121).build() | |||
) | |||
.build()) | |||
.build(), | |||
DumbComponent.builder(MODULE, 12) | |||
.addChildren( | |||
DumbComponent.builder(DIRECTORY, 121) | |||
.addChildren( | |||
DumbComponent.builder(FILE, 1211).build() | |||
) | |||
.build() | |||
).build() | |||
).build(); | |||
@Test | |||
public void verify_preOrder() { | |||
TestPathAwareVisitor underTest = new TestPathAwareVisitor(PRE_ORDER); | |||
underTest.visit(SOME_TREE_ROOT); | |||
Iterator<CallRecord> expected = of( | |||
newCallRecord("visitAny", 1, null, of(1)), | |||
newCallRecord("visitProject", 1, null, of(1)), | |||
newCallRecord("visitAny", 11, 1, of(11, 1)), | |||
newCallRecord("visitModule", 11, 1, of(11, 1)), | |||
newCallRecord("visitAny", 111, 11, of(111, 11, 1)), | |||
newCallRecord("visitDirectory", 111, 11, of(111, 11, 1)), | |||
newCallRecord("visitAny", 1111, 111, of(1111, 111, 11, 1)), | |||
newCallRecord("visitFile", 1111, 111, of(1111, 111, 11, 1)), | |||
newCallRecord("visitAny", 1112, 111, of(1112, 111, 11, 1)), | |||
newCallRecord("visitFile", 1112, 111, of(1112, 111, 11, 1)), | |||
newCallRecord("visitAny", 112, 11, of(112, 11, 1)), | |||
newCallRecord("visitDirectory", 112, 11, of(112, 11, 1)), | |||
newCallRecord("visitAny", 1121, 112, of(1121, 112, 11, 1)), | |||
newCallRecord("visitFile", 1121, 112, of(1121, 112, 11, 1)), | |||
newCallRecord("visitAny", 12, 1, of(12, 1)), | |||
newCallRecord("visitModule", 12, 1, of(12, 1)), | |||
newCallRecord("visitAny", 121, 12, of(121, 12, 1)), | |||
newCallRecord("visitDirectory", 121, 12, of(121, 12, 1)), | |||
newCallRecord("visitAny", 1211, 121, of(1211, 121, 12, 1)), | |||
newCallRecord("visitFile", 1211, 121, of(1211, 121, 12, 1)) | |||
).iterator(); | |||
verifyCallRecords(expected, underTest.callsRecords.iterator()); | |||
} | |||
@Test | |||
public void verify_postOrder() { | |||
TestPathAwareVisitor underTest = new TestPathAwareVisitor(POST_ORDER); | |||
underTest.visit(SOME_TREE_ROOT); | |||
Iterator<CallRecord> expected = of( | |||
newCallRecord("visitAny", 1111, 111, of(1111, 111, 11, 1)), | |||
newCallRecord("visitFile", 1111, 111, of(1111, 111, 11, 1)), | |||
newCallRecord("visitAny", 1112, 111, of(1112, 111, 11, 1)), | |||
newCallRecord("visitFile", 1112, 111, of(1112, 111, 11, 1)), | |||
newCallRecord("visitAny", 111, 11, of(111, 11, 1)), | |||
newCallRecord("visitDirectory", 111, 11, of(111, 11, 1)), | |||
newCallRecord("visitAny", 1121, 112, of(1121, 112, 11, 1)), | |||
newCallRecord("visitFile", 1121, 112, of(1121, 112, 11, 1)), | |||
newCallRecord("visitAny", 112, 11, of(112, 11, 1)), | |||
newCallRecord("visitDirectory", 112, 11, of(112, 11, 1)), | |||
newCallRecord("visitAny", 11, 1, of(11, 1)), | |||
newCallRecord("visitModule", 11, 1, of(11, 1)), | |||
newCallRecord("visitAny", 1211, 121, of(1211, 121, 12, 1)), | |||
newCallRecord("visitFile", 1211, 121, of(1211, 121, 12, 1)), | |||
newCallRecord("visitAny", 121, 12, of(121, 12, 1)), | |||
newCallRecord("visitDirectory", 121, 12, of(121, 12, 1)), | |||
newCallRecord("visitAny", 12, 1, of(12, 1)), | |||
newCallRecord("visitModule", 12, 1, of(12, 1)), | |||
newCallRecord("visitAny", 1, null, of(1)), | |||
newCallRecord("visitProject", 1, null, of(1)) | |||
).iterator(); | |||
verifyCallRecords(expected, underTest.callsRecords.iterator()); | |||
} | |||
private static void verifyCallRecords(Iterator<CallRecord> expected, Iterator<CallRecord> actual) { | |||
while (expected.hasNext()) { | |||
assertThat(actual.next()).isEqualTo(expected.next()); | |||
} | |||
} | |||
private static CallRecord newCallRecord(String method, int currentRef, @Nullable Integer parentRef, List<Integer> path) { | |||
return new CallRecord(method, currentRef, currentRef, parentRef, ROOT_REF, path); | |||
} | |||
private static class TestPathAwareVisitor extends PathAwareVisitor<Integer> { | |||
private final List<CallRecord> callsRecords = new ArrayList<>(); | |||
public TestPathAwareVisitor(ComponentVisitor.Order order) { | |||
super(FILE, order, new SimpleStackElementFactory<Integer>() { | |||
@Override | |||
public Integer createForAny(Component component) { | |||
return component.getRef(); | |||
} | |||
}); | |||
} | |||
@Override | |||
protected void visitProject(Component project, Path<Integer> path) { | |||
callsRecords.add(newCallRecord(project, path, "visitProject")); | |||
} | |||
@Override | |||
protected void visitModule(Component module, Path<Integer> path) { | |||
callsRecords.add(newCallRecord(module, path, "visitModule")); | |||
} | |||
@Override | |||
protected void visitDirectory(Component directory, Path<Integer> path) { | |||
callsRecords.add(newCallRecord(directory, path, "visitDirectory")); | |||
} | |||
@Override | |||
protected void visitFile(Component file, Path<Integer> path) { | |||
callsRecords.add(newCallRecord(file, path, "visitFile")); | |||
} | |||
@Override | |||
protected void visitUnknown(Component unknownComponent, Path<Integer> path) { | |||
callsRecords.add(newCallRecord(unknownComponent, path, "visitUnknown")); | |||
} | |||
@Override | |||
protected void visitAny(Component component, Path<Integer> path) { | |||
callsRecords.add(newCallRecord(component, path, "visitAny")); | |||
} | |||
private static CallRecord newCallRecord(Component project, Path<Integer> path, String method) { | |||
return new CallRecord(method, project.getRef(), path.current(), getParent(path), path.root(), | |||
toValueList(path)); | |||
} | |||
private static List<Integer> toValueList(Path<Integer> path) { | |||
return from(path.getCurrentPath()).transform(new Function<PathElement<Integer>, Integer>() { | |||
@Nonnull | |||
@Override | |||
public Integer apply(@Nonnull PathElement<Integer> input) { | |||
return input.getElement(); | |||
} | |||
}).toList(); | |||
} | |||
private static Integer getParent(Path<Integer> path) { | |||
try { | |||
Integer parent = path.parent(); | |||
checkArgument(parent != null, "Path.parent returned a null value!"); | |||
return parent; | |||
} catch (NoSuchElementException e) { | |||
return null; | |||
} | |||
} | |||
} | |||
private static class CallRecord { | |||
private final String method; | |||
private final int ref; | |||
private final int current; | |||
@CheckForNull | |||
private final Integer parent; | |||
private final int root; | |||
private final List<Integer> path; | |||
private CallRecord(String method, int ref, int current, @Nullable Integer parent, int root, List<Integer> path) { | |||
this.method = method; | |||
this.ref = ref; | |||
this.current = current; | |||
this.parent = parent; | |||
this.root = root; | |||
this.path = path; | |||
} | |||
@Override | |||
public boolean equals(@Nullable Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o == null || getClass() != o.getClass()) { | |||
return false; | |||
} | |||
CallRecord that = (CallRecord) o; | |||
return Objects.equals(ref, that.ref) && | |||
Objects.equals(current, that.current) && | |||
Objects.equals(root, that.root) && | |||
Objects.equals(method, that.method) && | |||
Objects.equals(parent, that.parent) && | |||
Objects.equals(path, that.path); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return Objects.hash(method, ref, current, parent, root, path); | |||
} | |||
@Override | |||
public String toString() { | |||
return "{" + | |||
"method='" + method + '\'' + | |||
", ref=" + ref + | |||
", current=" + current + | |||
", parent=" + parent + | |||
", root=" + root + | |||
", path=" + path + | |||
'}'; | |||
} | |||
} | |||
} |
@@ -29,7 +29,7 @@ import static org.sonar.server.computation.component.Component.Type.DIRECTORY; | |||
import static org.sonar.server.computation.component.Component.Type.FILE; | |||
import static org.sonar.server.computation.component.Component.Type.MODULE; | |||
import static org.sonar.server.computation.component.Component.Type.PROJECT; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER; | |||
public class PostOrderDepthTraversalTypeAwareVisitorTest { | |||
@@ -29,7 +29,7 @@ import static org.sonar.server.computation.component.Component.Type.DIRECTORY; | |||
import static org.sonar.server.computation.component.Component.Type.FILE; | |||
import static org.sonar.server.computation.component.Component.Type.MODULE; | |||
import static org.sonar.server.computation.component.Component.Type.PROJECT; | |||
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | |||
public class PreOrderDepthTraversalTypeAwareVisitorTest { | |||