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
committed by
Andreas Dangel
parent
9d0a6b7f4b
commit
c2d22a1bdf
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user