Fixes #1458 Performance degradation scanning large XML files with XPath custom rules

This commit is contained in:
Andreas Dangel
2016-04-01 20:52:38 +02:00
parent c3f98356f8
commit 494719d8ea
2 changed files with 42 additions and 23 deletions

View File

@ -3,8 +3,11 @@
*/ */
package net.sourceforge.pmd.lang.xml.ast; package net.sourceforge.pmd.lang.xml.ast;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -21,8 +24,8 @@ import org.w3c.dom.ProcessingInstruction;
*/ */
class DOMLineNumbers { class DOMLineNumbers {
private final Document document; private final Document document;
private final String xmlString; private String xmlString;
private Map<Integer, Integer> lines; private List<Integer> lines;
public DOMLineNumbers(Document document, String xmlString) { public DOMLineNumbers(Document document, String xmlString) {
this.document = document; this.document = document;
@ -123,47 +126,62 @@ class DOMLineNumbers {
} }
private void setBeginLocation(Node n, int index) { private void setBeginLocation(Node n, int index) {
if (n != null) { if (n != null) {
n.setUserData(XmlNode.BEGIN_LINE, toLine(index), null); int line = toLine(index);
n.setUserData(XmlNode.BEGIN_COLUMN, toColumn(index), null); n.setUserData(XmlNode.BEGIN_LINE, line, null);
n.setUserData(XmlNode.BEGIN_COLUMN, toColumn(line, index), null);
} }
} }
private void setEndLocation(Node n, int index) { private void setEndLocation(Node n, int index) {
if (n != null) { if (n != null) {
n.setUserData(XmlNode.END_LINE, toLine(index), null); int line = toLine(index);
n.setUserData(XmlNode.END_COLUMN, toColumn(index), null); n.setUserData(XmlNode.END_LINE, line, null);
n.setUserData(XmlNode.END_COLUMN, toColumn(line, index), null);
} }
} }
/**
* Calculates a list with the file offsets for each line.
*/
private void calculateLinesMap() { private void calculateLinesMap() {
lines = new TreeMap<Integer, Integer>(); lines = new ArrayList<Integer>();
int index = -1; int index = -1;
int count = StringUtils.countMatches(xmlString, "\n"); int count = StringUtils.countMatches(xmlString, "\n");
for (int line = 1; line <= count; line++) { for (int line = 1; line <= count; line++) {
lines.put(line, index + 1); lines.add(index + 1);
index = xmlString.indexOf("\n", index + 1); index = xmlString.indexOf("\n", index + 1); // fast forward till end of current line
} }
lines.put(count + 1, index + 1); lines.add(index + 1);
} }
private int toLine(int index) { private int toLine(int index) {
int line = 1; int low = 0;
for (Map.Entry<Integer, Integer> e : lines.entrySet()) { int high = lines.size() - 1;
line = e.getKey();
if (e.getValue() > index) { // binary search the best match
line--; while (low <= high) {
break; int middle = (low + high) / 2;
int middleStart = lines.get(middle);
if (middleStart == index) {
return middle + 1; // found
}
if (middleStart > index) {
high = middle - 1;
} else {
low = middle + 1;
} }
} }
return line;
return low; // not found or last checked line, which is the best match;
} }
private int toColumn(int index) {
int line = toLine(index); private int toColumn(int line, int index) {
Integer lineStart = lines.get(line); Integer lineStart = lines.get(line - 1);
if (lineStart == null) { if (lineStart == null) {
lineStart = lines.get(lines.size() - 1); lineStart = lines.get(lines.size() - 1);
} }
int column = index - lineStart; int column = index - lineStart;
return column + 1; return column + 1;
} }
} }

View File

@ -48,6 +48,7 @@
* [#1456](https://sourceforge.net/p/pmd/bugs/1456/): UnusedFormalParameter should ignore overriding methods * [#1456](https://sourceforge.net/p/pmd/bugs/1456/): UnusedFormalParameter should ignore overriding methods
* General * General
* [#1455](https://sourceforge.net/p/pmd/bugs/1455/): PMD doesn't handle Java 8 explicit receiver parameters * [#1455](https://sourceforge.net/p/pmd/bugs/1455/): PMD doesn't handle Java 8 explicit receiver parameters
* [#1458](https://sourceforge.net/p/pmd/bugs/1458/): Performance degradation scanning large XML files with XPath custom rules
* [#1461](https://sourceforge.net/p/pmd/bugs/1461/): Possible threading issue due to PR#75 * [#1461](https://sourceforge.net/p/pmd/bugs/1461/): Possible threading issue due to PR#75
**API Changes:** **API Changes:**