Improve symboltable codebase

- Move shared code to pmd-core
 - Allow search methods to stop searching when they want to
 - If we are looking for a variable declaration, just search among those and not all name declarations
 - This is roughtly another 10% improvement on symbol table performance
This commit is contained in:
Juan Martín Sotuyo Dodero
2016-12-12 16:32:26 -03:00
committed by Andreas Dangel
parent b6bc06d3d2
commit b950929b7c
22 changed files with 132 additions and 215 deletions

View File

@ -0,0 +1,22 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.symboltable;
import java.util.Iterator;
import net.sourceforge.pmd.util.SearchFunction;
public final class Applier {
private Applier() {
// utility class
}
public static <E> void apply(SearchFunction<E> f, Iterator<? extends E> i) {
while (i.hasNext() && f.applyTo(i.next())) {
// Nothing to do
}
}
}

View File

@ -1,16 +1,16 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.plsql.symboltable;
package net.sourceforge.pmd.lang.symboltable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.util.UnaryFunction;
import net.sourceforge.pmd.util.SearchFunction;
public class ImageFinderFunction implements UnaryFunction<NameDeclaration> {
public class ImageFinderFunction implements SearchFunction<NameDeclaration> {
private Set<String> images = new HashSet<>();
private NameDeclaration decl;
@ -23,10 +23,13 @@ public class ImageFinderFunction implements UnaryFunction<NameDeclaration> {
images.addAll(imageList);
}
public void applyTo(NameDeclaration nameDeclaration) {
@Override
public boolean applyTo(NameDeclaration nameDeclaration) {
if (images.contains(nameDeclaration.getImage())) {
decl = nameDeclaration;
return false;
}
return true;
}
public NameDeclaration getDecl() {

View File

@ -0,0 +1,14 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.util;
public interface SearchFunction<E> {
/**
* Applies the search function over a single element.
* @param o The element to analyze.
* @return True if the search should continue, false otherwhise.
*/
boolean applyTo(E o);
}

View File

@ -1,8 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.util;
public interface UnaryFunction<E> {
void applyTo(E o);
}

View File

@ -0,0 +1,62 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.symboltable;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import net.sourceforge.pmd.util.SearchFunction;
public class ApplierTest {
private static class MyFunction implements SearchFunction<Object> {
private int numCallbacks = 0;
private final int maxCallbacks;
MyFunction(int maxCallbacks) {
this.maxCallbacks = maxCallbacks;
}
@Override
public boolean applyTo(Object o) {
this.numCallbacks++;
return numCallbacks < maxCallbacks;
}
public int getNumCallbacks() {
return this.numCallbacks;
}
}
@Test
public void testSimple() {
MyFunction f = new MyFunction(Integer.MAX_VALUE);
List<Object> l = new ArrayList<>();
l.add(new Object());
l.add(new Object());
l.add(new Object());
Applier.apply(f, l.iterator());
assertEquals(l.size(), f.getNumCallbacks());
}
@Test
public void testLimit() {
MyFunction f = new MyFunction(2);
List<Object> l = new ArrayList<>();
l.add(new Object());
l.add(new Object());
l.add(new Object());
Applier.apply(f, l.iterator());
assertEquals(2, f.getNumCallbacks());
}
public static junit.framework.Test suite() {
return new junit.framework.JUnit4TestAdapter(ApplierTest.class);
}
}

View File

@ -42,7 +42,7 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode {
}
public List<NameOccurrence> getUsages() {
return getScope().getDeclarations().get(nameDeclaration);
return getScope().getDeclarations(VariableNameDeclaration.class).get(nameDeclaration);
}
public void bumpArrayDepth() {

View File

@ -1,21 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.symboltable;
import java.util.Iterator;
import net.sourceforge.pmd.util.UnaryFunction;
public final class Applier {
private Applier() {
// utility class
}
public static <E> void apply(UnaryFunction<E> f, Iterator<? extends E> i) {
while (i.hasNext()) {
f.applyTo(i.next());
}
}
}

View File

@ -36,6 +36,8 @@ import net.sourceforge.pmd.lang.java.ast.ASTTypeParameter;
import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.ast.JavaParserTreeConstants;
import net.sourceforge.pmd.lang.symboltable.Applier;
import net.sourceforge.pmd.lang.symboltable.ImageFinderFunction;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
import net.sourceforge.pmd.lang.symboltable.Scope;

View File

@ -5,9 +5,9 @@ package net.sourceforge.pmd.lang.java.symboltable;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
import net.sourceforge.pmd.util.UnaryFunction;
import net.sourceforge.pmd.util.SearchFunction;
public class DeclarationFinderFunction implements UnaryFunction<NameDeclaration> {
public class DeclarationFinderFunction implements SearchFunction<NameDeclaration> {
private NameOccurrence occurrence;
private NameDeclaration decl;
@ -16,10 +16,13 @@ public class DeclarationFinderFunction implements UnaryFunction<NameDeclaration>
this.occurrence = occurrence;
}
public void applyTo(NameDeclaration nameDeclaration) {
@Override
public boolean applyTo(NameDeclaration nameDeclaration) {
if (isDeclaredBefore(nameDeclaration) && isSameName(nameDeclaration)) {
decl = nameDeclaration;
return false;
}
return true;
}
private boolean isDeclaredBefore(NameDeclaration nameDeclaration) {

View File

@ -1,35 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.symboltable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.util.UnaryFunction;
public class ImageFinderFunction implements UnaryFunction<NameDeclaration> {
private Set<String> images = new HashSet<>();
private NameDeclaration decl;
public ImageFinderFunction(String img) {
images.add(img);
}
public ImageFinderFunction(List<String> imageList) {
images.addAll(imageList);
}
public void applyTo(NameDeclaration nameDeclaration) {
if (images.contains(nameDeclaration.getImage())) {
decl = nameDeclaration;
}
}
public NameDeclaration getDecl() {
return this.decl;
}
}

View File

@ -3,6 +3,7 @@
*/
package net.sourceforge.pmd.lang.java.symboltable;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -10,6 +11,7 @@ import java.util.Set;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.symboltable.Applier;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
@ -48,10 +50,10 @@ public class LocalScope extends AbstractJavaScope {
}
public Set<NameDeclaration> findVariableHere(JavaNameOccurrence occurrence) {
Set<NameDeclaration> result = new HashSet<>();
if (occurrence.isThisOrSuper() || occurrence.isMethodOrConstructorInvocation()) {
return result;
return Collections.emptySet();
}
Set<NameDeclaration> result = new HashSet<>();
DeclarationFinderFunction finder = new DeclarationFinderFunction(occurrence);
Applier.apply(finder, getVariableDeclarations().keySet().iterator());
if (finder.getDecl() != null) {

View File

@ -11,6 +11,8 @@ import java.util.Set;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.symboltable.Applier;
import net.sourceforge.pmd.lang.symboltable.ImageFinderFunction;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;

View File

@ -13,6 +13,8 @@ import java.util.Set;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
import net.sourceforge.pmd.lang.symboltable.Applier;
import net.sourceforge.pmd.lang.symboltable.ImageFinderFunction;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
import net.sourceforge.pmd.lang.symboltable.Scope;

View File

@ -1,31 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.symboltable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
import net.sourceforge.pmd.util.UnaryFunction;
public class VariableUsageFinderFunction implements UnaryFunction<NameDeclaration> {
private Map<NameDeclaration, List<NameOccurrence>> results = new HashMap<>();
private Map<NameDeclaration, List<NameOccurrence>> decls;
public VariableUsageFinderFunction(Map<NameDeclaration, List<NameOccurrence>> decls) {
this.decls = decls;
}
public void applyTo(NameDeclaration o) {
results.put(o, decls.get(o));
}
public Map<NameDeclaration, List<NameOccurrence>> getUsed() {
return results;
}
}

View File

@ -1,41 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.symboltable;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.pmd.lang.java.symboltable.Applier;
import net.sourceforge.pmd.util.UnaryFunction;
import org.junit.Test;
public class ApplierTest {
private static class MyFunction implements UnaryFunction<Object> {
private boolean gotCallback;
public void applyTo(Object o) {
this.gotCallback = true;
}
public boolean gotCallback() {
return this.gotCallback;
}
}
@Test
public void testSimple() {
MyFunction f = new MyFunction();
List<Object> l = new ArrayList<>();
l.add(new Object());
Applier.apply(f, l.iterator());
assertTrue(f.gotCallback());
}
public static junit.framework.Test suite() {
return new junit.framework.JUnit4TestAdapter(ApplierTest.class);
}
}

View File

@ -9,8 +9,7 @@ import java.util.ArrayList;
import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.symboltable.ImageFinderFunction;
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
import net.sourceforge.pmd.lang.symboltable.ImageFinderFunction;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import org.junit.Test;

View File

@ -1,45 +0,0 @@
package net.sourceforge.pmd.lang.java.symboltable;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.ast.DummyJavaNode;
import net.sourceforge.pmd.lang.java.symboltable.Applier;
import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
import net.sourceforge.pmd.lang.java.symboltable.VariableUsageFinderFunction;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
import org.junit.Test;
public class VariableUsageFinderFunctionTest {
@Test
public void testLookingForUsed() {
ASTVariableDeclaratorId variableDeclarationIdNode = new ASTVariableDeclaratorId(1);
variableDeclarationIdNode.setImage("x");
VariableNameDeclaration nameDeclaration = new VariableNameDeclaration(variableDeclarationIdNode);
List<NameOccurrence> nameOccurrences = new ArrayList<>();
nameOccurrences.add(new JavaNameOccurrence(new DummyJavaNode(2), "x"));
Map<NameDeclaration, List<NameOccurrence>> declarations = new HashMap<>();
declarations.put(nameDeclaration, nameOccurrences);
List<NameDeclaration> vars = new ArrayList<>();
vars.add(nameDeclaration);
VariableUsageFinderFunction f = new VariableUsageFinderFunction(declarations);
Applier.apply(f, vars.iterator());
Map<NameDeclaration, List<NameOccurrence>> p = f.getUsed();
assertEquals(1, p.size());
}
public static junit.framework.Test suite() {
return new junit.framework.JUnit4TestAdapter(VariableUsageFinderFunctionTest.class);
}
}

View File

@ -1,21 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.plsql.symboltable;
import java.util.Iterator;
import net.sourceforge.pmd.util.UnaryFunction;
public final class Applier {
private Applier() {
// utility class
}
public static <E> void apply(UnaryFunction<E> f, Iterator<? extends E> i) {
while (i.hasNext()) {
f.applyTo(i.next());
}
}
}

View File

@ -15,6 +15,8 @@ import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.plsql.ast.ASTName;
import net.sourceforge.pmd.lang.plsql.ast.AbstractPLSQLNode;
import net.sourceforge.pmd.lang.symboltable.AbstractScope;
import net.sourceforge.pmd.lang.symboltable.Applier;
import net.sourceforge.pmd.lang.symboltable.ImageFinderFunction;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;

View File

@ -11,6 +11,8 @@ import java.util.Set;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.plsql.ast.ASTName;
import net.sourceforge.pmd.lang.symboltable.AbstractScope;
import net.sourceforge.pmd.lang.symboltable.Applier;
import net.sourceforge.pmd.lang.symboltable.ImageFinderFunction;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;

View File

@ -12,6 +12,8 @@ import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.plsql.ast.ASTName;
import net.sourceforge.pmd.lang.plsql.ast.AbstractPLSQLNode;
import net.sourceforge.pmd.lang.symboltable.AbstractScope;
import net.sourceforge.pmd.lang.symboltable.Applier;
import net.sourceforge.pmd.lang.symboltable.ImageFinderFunction;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;

View File

@ -4,6 +4,8 @@
package net.sourceforge.pmd.lang.plsql.symboltable;
import net.sourceforge.pmd.lang.symboltable.AbstractScope;
import net.sourceforge.pmd.lang.symboltable.Applier;
import net.sourceforge.pmd.lang.symboltable.ImageFinderFunction;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;