Make Mark's code snippet lazy

- This greatly reduces the memory footprint during analysis,
    addressing part of the issues raised ay #185
 - Rendering is still done to a single String which is then either printed
    to STDOUT or a file, this stiill needs refactoring.
This commit is contained in:
Juan Martín Sotuyo Dodero
2017-01-18 17:01:28 -03:00
committed by Andreas Dangel
parent 9d0a6b7f4b
commit c2d22a1bdf
8 changed files with 60 additions and 26 deletions

View File

@ -6,7 +6,7 @@ package net.sourceforge.pmd.cpd;
public class Mark implements Comparable<Mark> {
private TokenEntry token;
private int lineCount;
private String code;
private SourceCode code;
public Mark(TokenEntry token) {
this.token = token;
@ -37,10 +37,10 @@ public class Mark implements Comparable<Mark> {
}
public String getSourceCodeSlice() {
return this.code;
return this.code.getSlice(getBeginLine(), getEndLine());
}
public void setSoureCodeSlice(String code) {
public void setSourceCode(SourceCode code) {
this.code = code;
}

View File

@ -10,7 +10,7 @@ import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class Match implements Comparable<Match> {
public class Match implements Comparable<Match>, Iterable<Mark> {
private int tokenCount;
private Set<Mark> markSet = new TreeSet<>();
@ -72,6 +72,7 @@ public class Match implements Comparable<Match> {
return this.getMark(0).getSourceCodeSlice();
}
@Override
public Iterator<Mark> iterator() {
return markSet.iterator();
}

View File

@ -63,6 +63,7 @@ public class MatchAlgorithm {
for (Iterator<Object> i = markGroups.values().iterator(); i.hasNext();) {
Object o = i.next();
if (o instanceof List) {
@SuppressWarnings("unchecked")
List<TokenEntry> l = (List<TokenEntry>) o;
Collections.reverse(l);
matchCollector.collect(l);
@ -73,16 +74,13 @@ public class MatchAlgorithm {
matches = matchCollector.getMatches();
matchCollector = null;
for (Match match : matches) {
for (Iterator<Mark> occurrences = match.iterator(); occurrences.hasNext();) {
Mark mark = occurrences.next();
for (Mark mark : match) {
TokenEntry token = mark.getToken();
int lineCount = tokens.getLineCount(token, match);
mark.setLineCount(lineCount);
SourceCode sourceCode = source.get(token.getTokenSrcID());
String code = sourceCode.getSlice(mark.getBeginLine(), mark.getEndLine());
mark.setSoureCodeSlice(code);
mark.setSourceCode(sourceCode);
}
}
cpdListener.phaseUpdate(CPDListener.DONE);
@ -109,6 +107,7 @@ public class MatchAlgorithm {
l.add(token);
markGroups.put(token, l);
} else {
@SuppressWarnings("unchecked")
List<TokenEntry> l = (List<TokenEntry>) o;
l.add(token);
}

View File

@ -3,10 +3,10 @@
*/
package net.sourceforge.pmd.cpd;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.Reader;
import java.io.StringReader;
import java.lang.ref.SoftReference;
@ -16,7 +16,6 @@ import java.util.List;
import net.sourceforge.pmd.PMD;
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.BOMInputStream;
public class SourceCode {
@ -36,25 +35,57 @@ public class SourceCode {
return code.get();
}
public List<String> getCodeSlice(int startLine, int endLine) {
List<String> c = null;
if (code != null) {
c = code.get();
}
if (c != null) {
return c.subList(startLine, endLine);
}
return load(startLine, endLine);
}
public abstract String getFileName();
protected abstract Reader getReader() throws Exception;
protected List<String> load() {
LineNumberReader lnr = null;
try {
lnr = new LineNumberReader(getReader());
try (BufferedReader reader = new BufferedReader(getReader())) {
List<String> lines = new ArrayList<>();
String currentLine;
while ((currentLine = lnr.readLine()) != null) {
while ((currentLine = reader.readLine()) != null) {
lines.add(currentLine);
}
return lines;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Problem while reading " + getFileName() + ":" + e.getMessage());
} finally {
IOUtils.closeQuietly(lnr);
}
}
protected List<String> load(int startLine, int endLine) {
try (BufferedReader reader = new BufferedReader(getReader())) {
int linesToRead = endLine - startLine;
List<String> lines = new ArrayList<>(linesToRead);
// Skip lines until we reach the start point
for (int i = 0; i < startLine; i++) {
reader.readLine();
}
String currentLine;
while ((currentLine = reader.readLine()) != null) {
lines.add(currentLine);
if (lines.size() == linesToRead) {
break;
}
}
return lines;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Problem while reading " + getFileName() + ":" + e.getMessage());
}
}
}
@ -164,13 +195,14 @@ public class SourceCode {
}
public String getSlice(int startLine, int endLine) {
List<String> lines = cl.getCodeSlice(startLine - 1, endLine);
StringBuilder sb = new StringBuilder();
List<String> lines = cl.getCode();
for (int i = startLine == 0 ? startLine : startLine - 1; i < endLine && i < lines.size(); i++) {
for (String line : lines) {
if (sb.length() != 0) {
sb.append(PMD.EOL);
}
sb.append(lines.get(i));
sb.append(line);
}
return sb.toString();
}

View File

@ -36,7 +36,7 @@ public class CSVRendererTest {
Mark result = new Mark(new TokenEntry(image, tokenSrcID, beginLine));
result.setLineCount(lineCount);
result.setSoureCodeSlice(code);
result.setSourceCode(new SourceCode(new SourceCode.StringCodeLoader(code)));
return result;
}

View File

@ -7,6 +7,8 @@ import static org.junit.Assert.assertEquals;
import org.junit.Test;
import net.sourceforge.pmd.cpd.SourceCode.StringCodeLoader;
public class MarkTest {
@Test
@ -19,7 +21,7 @@ public class MarkTest {
int lineCount = 10;
mark.setLineCount(lineCount);
String codeFragment = "code fragment";
mark.setSoureCodeSlice(codeFragment);
mark.setSourceCode(new SourceCode(new StringCodeLoader(codeFragment)));
assertEquals(token, mark.getToken());
assertEquals(filename, mark.getFilename());

View File

@ -55,7 +55,7 @@ public class MatchTest {
Mark result = new Mark(new TokenEntry(image, tokenSrcID, beginLine));
result.setLineCount(lineCount);
result.setSoureCodeSlice(code);
result.setSourceCode(new SourceCode(new SourceCode.StringCodeLoader(code)));
return result;
}

View File

@ -51,7 +51,7 @@ public class XMLRendererTest {
List<Match> list = new ArrayList<>();
int lineCount = 6;
String codeFragment = "code\nfragment";
Mark mark1 = createMark("public", "/var/Foo.java", 48, lineCount, codeFragment);
Mark mark1 = createMark("public", "/var/Foo.java", 1, lineCount, codeFragment);
Mark mark2 = createMark("stuff", "/var/Foo.java", 73, lineCount, codeFragment);
Match match = new Match(75, mark1, mark2);
@ -66,7 +66,7 @@ public class XMLRendererTest {
file = file.getNextSibling();
}
if (file != null) {
assertEquals("48", file.getAttributes().getNamedItem("line").getNodeValue());
assertEquals("1", file.getAttributes().getNamedItem("line").getNodeValue());
assertEquals("/var/Foo.java", file.getAttributes().getNamedItem("path").getNodeValue());
file = file.getNextSibling();
while (file != null && file.getNodeType() != Node.ELEMENT_NODE) {
@ -128,7 +128,7 @@ public class XMLRendererTest {
Mark result = new Mark(new TokenEntry(image, tokenSrcID, beginLine));
result.setLineCount(lineCount);
result.setSoureCodeSlice(code);
result.setSourceCode(new SourceCode(new SourceCode.StringCodeLoader(code)));
return result;
}