Fixes #1458 Performance degradation scanning large XML files with XPath custom rules
This commit is contained in:
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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:**
|
||||||
|
Reference in New Issue
Block a user