@@ -176,7 +176,7 @@ public class SonarEngine extends CpdEngine { | |||
for (ClonePart part : clone.getCloneParts()) { | |||
if (part.getResourceId().equals(origin.getResourceId())) { | |||
duplicatedBlocks++; | |||
for (int duplicatedLine = part.getLineStart(); duplicatedLine < part.getLineStart() + part.getLines(); duplicatedLine++) { | |||
for (int duplicatedLine = part.getStartLine(); duplicatedLine < part.getEndLine() + part.getLines(); duplicatedLine++) { | |||
duplicatedLines.add(duplicatedLine); | |||
} | |||
} | |||
@@ -188,7 +188,7 @@ public class SonarEngine extends CpdEngine { | |||
for (CloneGroup clone : clones) { | |||
xml.append("<g>"); | |||
for (ClonePart part : clone.getCloneParts()) { | |||
xml.append("<b s=\"").append(part.getLineStart()) | |||
xml.append("<b s=\"").append(part.getStartLine()) | |||
.append("\" l=\"").append(part.getLines()) | |||
.append("\" r=\"").append(part.getResourceId()) | |||
.append("\"/>"); |
@@ -101,12 +101,12 @@ public class DbDuplicationsIndex { | |||
List<DuplicationUnitDto> units = Lists.newArrayList(); | |||
for (Block block : blocks) { | |||
DuplicationUnitDto unit = new DuplicationUnitDto( | |||
currentProjectSnapshotId, | |||
resourceSnapshotId, | |||
block.getBlockHash().toString(), | |||
block.getIndexInFile(), | |||
block.getFirstLineNumber(), | |||
block.getLastLineNumber()); | |||
currentProjectSnapshotId, | |||
resourceSnapshotId, | |||
block.getBlockHash().toString(), | |||
block.getIndexInFile(), | |||
block.getStartLine(), | |||
block.getEndLine()); | |||
units.add(unit); | |||
} | |||
@@ -28,6 +28,11 @@ import java.lang.ref.SoftReference; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* <p>Not intended to be instantiated by clients.</p> | |||
* | |||
* @since 2.2 | |||
*/ | |||
public class SourceCode { | |||
public static final String EOL = System.getProperty("line.separator", "\n"); | |||
@@ -150,6 +155,10 @@ public class SourceCode { | |||
return sb.toString(); | |||
} | |||
/** | |||
* Within Sonar Ecosystem - absolute path to file containing code, | |||
* whereas in fact existence of such file not guaranteed - see {@link StringCodeLoader}. | |||
*/ | |||
public String getFileName() { | |||
return cl.getFileName(); | |||
} |
@@ -28,11 +28,19 @@ import com.google.common.annotations.Beta; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
/** | |||
* @since 2.2 | |||
*/ | |||
public class TokenEntry implements Comparable<TokenEntry> { | |||
private final static Map<String, Integer> TOKENS = new HashMap<String, Integer>(); | |||
private static int tokenCount = 0; | |||
/** | |||
* Shared instance of end-of-file token. | |||
* | |||
* <p>Not intended to be used by clients - {@link #getEOF()} should be used instead.</p> | |||
*/ | |||
public static final TokenEntry EOF = new TokenEntry(); | |||
private String tokenSrcID; | |||
@@ -49,6 +57,11 @@ public class TokenEntry implements Comparable<TokenEntry> { | |||
this.value = ""; | |||
} | |||
/** | |||
* @param image string representation of token | |||
* @param tokenSrcID within Sonar Ecosystem - absolute path to file, otherwise current implementation of sonar-cpd-plugin will not work | |||
* @param beginLine number of line | |||
*/ | |||
public TokenEntry(String image, String tokenSrcID, int beginLine) { | |||
Integer i = TOKENS.get(image); | |||
if (i == null) { | |||
@@ -72,6 +85,9 @@ public class TokenEntry implements Comparable<TokenEntry> { | |||
return value; | |||
} | |||
/** | |||
* End-of-file token. | |||
*/ | |||
public static TokenEntry getEOF() { | |||
tokenCount++; | |||
return EOF; |
@@ -25,6 +25,11 @@ package net.sourceforge.pmd.cpd; | |||
import java.io.IOException; | |||
/** | |||
* @since 2.2 | |||
*/ | |||
public interface Tokenizer { | |||
void tokenize(SourceCode tokens, Tokens tokenEntries) throws IOException; | |||
} |
@@ -29,6 +29,11 @@ import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
/** | |||
* <p>Not intended to be instantiated by clients.</p> | |||
* | |||
* @since 2.2 | |||
*/ | |||
public class Tokens { | |||
private List<TokenEntry> tokens = new ArrayList<TokenEntry>(); |
@@ -31,20 +31,20 @@ public final class Block implements CodeFragment { | |||
private final String resourceId; | |||
private final ByteArray blockHash; | |||
private final int indexInFile; | |||
private final int firstLineNumber; | |||
private final int lastLineNumber; | |||
private final int startLine; | |||
private final int endLine; | |||
/** | |||
* Cache for hash code. | |||
*/ | |||
private int hash; | |||
public Block(String resourceId, ByteArray blockHash, int indexInFile, int firstLineNumber, int lastLineNumber) { | |||
public Block(String resourceId, ByteArray blockHash, int indexInFile, int startLine, int endLine) { | |||
this.resourceId = resourceId; | |||
this.blockHash = blockHash; | |||
this.indexInFile = indexInFile; | |||
this.firstLineNumber = firstLineNumber; | |||
this.lastLineNumber = lastLineNumber; | |||
this.startLine = startLine; | |||
this.endLine = endLine; | |||
} | |||
public Block(int indexInFile, int firstLineNumber, int lastLineNumber, String resourceId, String hash) { | |||
@@ -108,26 +108,12 @@ public final class Block implements CodeFragment { | |||
this.endUnit = endUnit; | |||
} | |||
/** | |||
* @deprecated in 2.14, use {@link #getStartLine()} instead | |||
*/ | |||
public int getFirstLineNumber() { | |||
return firstLineNumber; | |||
} | |||
/** | |||
* @deprecated in 2.14, use {@link #getEndLine()} instead | |||
*/ | |||
public int getLastLineNumber() { | |||
return lastLineNumber; | |||
} | |||
public int getStartLine() { | |||
return firstLineNumber; | |||
return startLine; | |||
} | |||
public int getEndLine() { | |||
return lastLineNumber; | |||
return endLine; | |||
} | |||
@Override | |||
@@ -139,8 +125,8 @@ public final class Block implements CodeFragment { | |||
return resourceId.equals(other.resourceId) | |||
&& blockHash.equals(other.blockHash) | |||
&& indexInFile == other.indexInFile | |||
&& firstLineNumber == other.firstLineNumber | |||
&& lastLineNumber == other.lastLineNumber; | |||
&& startLine == other.startLine | |||
&& endLine == other.endLine; | |||
} | |||
@Override | |||
@@ -150,8 +136,8 @@ public final class Block implements CodeFragment { | |||
h = resourceId.hashCode(); | |||
h = 31 * h + blockHash.hashCode(); | |||
h = 31 * h + indexInFile; | |||
h = 31 * h + firstLineNumber; | |||
h = 31 * h + lastLineNumber; | |||
h = 31 * h + startLine; | |||
h = 31 * h + endLine; | |||
hash = h; | |||
} | |||
return h; | |||
@@ -159,7 +145,7 @@ public final class Block implements CodeFragment { | |||
@Override | |||
public String toString() { | |||
return "'" + resourceId + "'[" + indexInFile + "|" + firstLineNumber + "-" + lastLineNumber + "]:" + blockHash; | |||
return "'" + resourceId + "'[" + indexInFile + "|" + startLine + "-" + endLine + "]:" + blockHash; | |||
} | |||
} |
@@ -19,19 +19,18 @@ | |||
*/ | |||
package org.sonar.duplications.detector.original; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Map; | |||
import com.google.common.collect.Lists; | |||
import com.google.common.collect.Maps; | |||
import org.sonar.duplications.block.Block; | |||
import org.sonar.duplications.block.ByteArray; | |||
import org.sonar.duplications.index.CloneGroup; | |||
import org.sonar.duplications.index.CloneIndex; | |||
import org.sonar.duplications.index.ClonePart; | |||
import com.google.common.collect.Lists; | |||
import com.google.common.collect.Maps; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Map; | |||
/** | |||
* Implementation of algorithm described in paper | |||
@@ -210,8 +209,8 @@ public final class OriginalCloneDetectionAlgorithm { | |||
Block lastBlock = pair[1]; | |||
ClonePart part = new ClonePart(firstBlock.getResourceId(), | |||
firstBlock.getIndexInFile(), | |||
firstBlock.getFirstLineNumber(), | |||
lastBlock.getLastLineNumber()); | |||
firstBlock.getStartLine(), | |||
lastBlock.getEndLine()); | |||
if (originResourceId.equals(part.getResourceId())) { | |||
if (origin == null) { |
@@ -89,8 +89,8 @@ public class DuplicationsCollector extends Search.Collector { | |||
ClonePart part = new ClonePart( | |||
firstBlock.getResourceId(), | |||
firstBlock.getIndexInFile(), | |||
firstBlock.getFirstLineNumber(), | |||
lastBlock.getLastLineNumber()); | |||
firstBlock.getStartLine(), | |||
lastBlock.getEndLine()); | |||
// TODO Godin: maybe use FastStringComparator here ? | |||
if (originResourceId.equals(part.getResourceId())) { // part from origin |
@@ -48,22 +48,6 @@ public class ClonePart implements CodeFragment { | |||
return startUnit; | |||
} | |||
/** | |||
* @deprecated in 2.14, use {@link #getStartLine()} instead | |||
*/ | |||
@Deprecated | |||
public int getLineStart() { | |||
return startLine; | |||
} | |||
/** | |||
* @deprecated in 2.14, use {@link #getEndLine()} instead | |||
*/ | |||
@Deprecated | |||
public int getLineEnd() { | |||
return endLine; | |||
} | |||
public int getStartLine() { | |||
return startLine; | |||
} |
@@ -184,8 +184,8 @@ public class PackedMemoryCloneIndex extends AbstractCloneIndex { | |||
blockData[offset++] = hash[i]; | |||
} | |||
blockData[offset++] = block.getIndexInFile(); | |||
blockData[offset++] = block.getFirstLineNumber(); | |||
blockData[offset++] = block.getLastLineNumber(); | |||
blockData[offset++] = block.getStartLine(); | |||
blockData[offset++] = block.getEndLine(); | |||
blockData[offset++] = block.getStartUnit(); | |||
blockData[offset] = block.getEndUnit(); | |||
@@ -19,13 +19,14 @@ | |||
*/ | |||
package net.sourceforge.pmd.cpd; | |||
import static org.hamcrest.Matchers.is; | |||
import static org.junit.Assert.*; | |||
import org.junit.Test; | |||
import java.io.File; | |||
import java.io.FilenameFilter; | |||
import java.io.IOException; | |||
import org.junit.Test; | |||
import static org.hamcrest.Matchers.is; | |||
import static org.junit.Assert.assertThat; | |||
/** | |||
* We use modified version of {@link AbstractLanguage} in comparison with PMD - it doesn't use package "net.sourceforge.pmd.util.filter", | |||
@@ -55,7 +56,13 @@ public class AbstractLanguageTest { | |||
@Test(expected = NullPointerException.class) | |||
public void shouldThrowException() { | |||
new AbstractLanguage(null, null) { | |||
new AbstractLanguage(null, (String) null) { | |||
}; | |||
} | |||
@Test(expected = NullPointerException.class) | |||
public void shouldAlsoThrowException() { | |||
new AbstractLanguage(null, (String[]) null) { | |||
}; | |||
} | |||
@@ -0,0 +1,52 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2008-2012 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar 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. | |||
* | |||
* Sonar 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 Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package net.sourceforge.pmd.cpd; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import static org.hamcrest.Matchers.equalTo; | |||
import static org.hamcrest.Matchers.sameInstance; | |||
import static org.junit.Assert.assertThat; | |||
public class TokenEntryTest { | |||
@Before | |||
public void setUp() { | |||
TokenEntry.clearImages(); | |||
} | |||
@Test | |||
public void testNewTokenEntry() { | |||
TokenEntry entry = new TokenEntry("token1", "src1", 1); | |||
assertThat(entry.getValue(), equalTo("token1")); | |||
assertThat(entry.getBeginLine(), equalTo(1)); | |||
entry = new TokenEntry("token2", "src2", 2); | |||
assertThat(entry.getValue(), equalTo("token2")); | |||
assertThat(entry.getBeginLine(), equalTo(2)); | |||
} | |||
@Test | |||
public void testGetEOF() { | |||
assertThat(TokenEntry.getEOF(), sameInstance(TokenEntry.getEOF())); | |||
} | |||
} |
@@ -19,19 +19,15 @@ | |||
*/ | |||
package org.sonar.duplications.block; | |||
import static org.hamcrest.Matchers.equalTo; | |||
import static org.hamcrest.Matchers.is; | |||
import static org.hamcrest.Matchers.not; | |||
import static org.hamcrest.Matchers.sameInstance; | |||
import static org.junit.Assert.assertThat; | |||
import com.google.common.collect.Lists; | |||
import org.junit.Test; | |||
import org.sonar.duplications.statement.Statement; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.junit.Test; | |||
import org.sonar.duplications.statement.Statement; | |||
import com.google.common.collect.Lists; | |||
import static org.hamcrest.Matchers.*; | |||
import static org.junit.Assert.assertThat; | |||
/** | |||
* Any implementation of {@link BlockChunker} should pass these test scenarios. | |||
@@ -91,11 +87,11 @@ public abstract class BlockChunkerTestCase { | |||
List<Block> blocks = chunker.chunk("resource", statements); | |||
assertThat(blocks.size(), is(4)); | |||
assertThat(blocks.get(0).getIndexInFile(), is(0)); | |||
assertThat(blocks.get(0).getFirstLineNumber(), is(0)); | |||
assertThat(blocks.get(0).getLastLineNumber(), is(2)); | |||
assertThat(blocks.get(0).getStartLine(), is(0)); | |||
assertThat(blocks.get(0).getEndLine(), is(2)); | |||
assertThat(blocks.get(1).getIndexInFile(), is(1)); | |||
assertThat(blocks.get(1).getFirstLineNumber(), is(1)); | |||
assertThat(blocks.get(1).getLastLineNumber(), is(3)); | |||
assertThat(blocks.get(1).getStartLine(), is(1)); | |||
assertThat(blocks.get(1).getEndLine(), is(3)); | |||
} | |||
@Test |
@@ -19,12 +19,7 @@ | |||
*/ | |||
package org.sonar.duplications.java; | |||
import static org.hamcrest.Matchers.is; | |||
import static org.junit.Assert.assertThat; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import com.google.common.base.Joiner; | |||
import org.junit.Test; | |||
import org.sonar.duplications.block.Block; | |||
import org.sonar.duplications.block.BlockChunker; | |||
@@ -37,7 +32,11 @@ import org.sonar.duplications.statement.Statement; | |||
import org.sonar.duplications.statement.StatementChunker; | |||
import org.sonar.duplications.token.TokenChunker; | |||
import com.google.common.base.Joiner; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import static org.hamcrest.Matchers.is; | |||
import static org.junit.Assert.assertThat; | |||
/** | |||
* From <a href="http://research.cs.queensu.ca/TechReports/Reports/2007-541.pdf">A Survey on Software Clone Detection Research (2007 year)</a>: | |||
@@ -71,13 +70,13 @@ public class JavaDuplicationsFunctionalTest { | |||
List<CloneGroup> duplications = detect2(fragment0, fragment1); | |||
assertThat(duplications.size(), is(1)); | |||
ClonePart part = duplications.get(0).getOriginPart(); | |||
assertThat(part.getLineStart(), is(1)); | |||
assertThat(part.getLineEnd(), is(5)); | |||
assertThat(part.getStartLine(), is(1)); | |||
assertThat(part.getEndLine(), is(5)); | |||
} | |||
/** | |||
* Supports only subset of Type 2. | |||
* | |||
* | |||
* @see #type2 | |||
* @see #literalsNormalization() | |||
*/ | |||
@@ -98,8 +97,8 @@ public class JavaDuplicationsFunctionalTest { | |||
List<CloneGroup> duplications = detect2(fragment0, fragment1); | |||
assertThat(duplications.size(), is(1)); | |||
ClonePart part = duplications.get(0).getOriginPart(); | |||
assertThat(part.getLineStart(), is(1)); | |||
assertThat(part.getLineEnd(), is(5)); | |||
assertThat(part.getStartLine(), is(1)); | |||
assertThat(part.getEndLine(), is(5)); | |||
} | |||
@Test | |||
@@ -146,8 +145,8 @@ public class JavaDuplicationsFunctionalTest { | |||
List<CloneGroup> duplications = detect2(fragment0, fragment1); | |||
assertThat(duplications.size(), is(1)); | |||
ClonePart part = duplications.get(0).getOriginPart(); | |||
assertThat(part.getLineStart(), is(3)); | |||
assertThat(part.getLineEnd(), is(6)); | |||
assertThat(part.getStartLine(), is(3)); | |||
assertThat(part.getEndLine(), is(6)); | |||
} | |||
private String source(String... lines) { |