Reduce memory allocations during symbol table
This commit is contained in:
Juan Martín Sotuyo Dodero
committed by
Andreas Dangel
parent
992e5547bb
commit
932ad7dd2b
@ -4,6 +4,7 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.symboltable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -12,15 +13,15 @@ import net.sourceforge.pmd.util.SearchFunction;
|
||||
|
||||
public class ImageFinderFunction implements SearchFunction<NameDeclaration> {
|
||||
|
||||
private Set<String> images = new HashSet<>();
|
||||
private final Set<String> images;
|
||||
private NameDeclaration decl;
|
||||
|
||||
public ImageFinderFunction(String img) {
|
||||
images.add(img);
|
||||
images = Collections.singleton(img);
|
||||
}
|
||||
|
||||
public ImageFinderFunction(List<String> imageList) {
|
||||
images.addAll(imageList);
|
||||
images = new HashSet<>(imageList);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.symboltable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@ -253,7 +252,7 @@ public class ClassScope extends AbstractJavaScope {
|
||||
Map<ClassNameDeclaration, List<NameOccurrence>> classDeclarations = getClassDeclarations();
|
||||
if (result.isEmpty() && !classDeclarations.isEmpty()) {
|
||||
for (ClassNameDeclaration innerClass : getClassDeclarations().keySet()) {
|
||||
Applier.apply(finder, innerClass.getScope().getDeclarations().keySet().iterator());
|
||||
Applier.apply(finder, innerClass.getScope().getDeclarations(VariableNameDeclaration.class).keySet().iterator());
|
||||
if (finder.getDecl() != null) {
|
||||
result.add(finder.getDecl());
|
||||
}
|
||||
@ -287,19 +286,24 @@ public class ClassScope extends AbstractJavaScope {
|
||||
methodDeclarator.jjtAddChild(formalParameters, 0);
|
||||
formalParameters.jjtSetParent(methodDeclarator);
|
||||
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
/*
|
||||
* jjtAddChild resizes it's child node list according to known indexes.
|
||||
* Going backwards makes sure the first time it gets the right size avoiding copies.
|
||||
*/
|
||||
for (int i = parameterTypes.length - 1; i >= 0; i--) {
|
||||
ASTFormalParameter formalParameter = new ASTFormalParameter(JavaParserTreeConstants.JJTFORMALPARAMETER);
|
||||
formalParameters.jjtAddChild(formalParameter, i);
|
||||
formalParameter.jjtSetParent(formalParameters);
|
||||
|
||||
ASTType type = new ASTType(JavaParserTreeConstants.JJTTYPE);
|
||||
formalParameter.jjtAddChild(type, 0);
|
||||
type.jjtSetParent(formalParameter);
|
||||
|
||||
ASTVariableDeclaratorId variableDeclaratorId = new ASTVariableDeclaratorId(JavaParserTreeConstants.JJTVARIABLEDECLARATORID);
|
||||
ASTVariableDeclaratorId variableDeclaratorId = new ASTVariableDeclaratorId(
|
||||
JavaParserTreeConstants.JJTVARIABLEDECLARATORID);
|
||||
variableDeclaratorId.setImage("arg" + i);
|
||||
formalParameter.jjtAddChild(variableDeclaratorId, 1);
|
||||
variableDeclaratorId.jjtSetParent(formalParameter);
|
||||
|
||||
ASTType type = new ASTType(JavaParserTreeConstants.JJTTYPE);
|
||||
formalParameter.jjtAddChild(type, 0);
|
||||
type.jjtSetParent(formalParameter);
|
||||
|
||||
if (PRIMITIVE_TYPES.contains(parameterTypes[i])) {
|
||||
ASTPrimitiveType primitiveType = new ASTPrimitiveType(JavaParserTreeConstants.JJTPRIMITIVETYPE);
|
||||
@ -363,20 +367,34 @@ public class ClassScope extends AbstractJavaScope {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<String> qualifiedNames = new LinkedHashSet<>();
|
||||
qualifiedNames.addAll(this.getEnclosingScope(SourceFileScope.class).getQualifiedTypeNames().keySet());
|
||||
qualifiedNames.addAll(this.getEnclosingScope(SourceFileScope.class).getExplicitImports());
|
||||
final SourceFileScope fileScope = getEnclosingScope(SourceFileScope.class);
|
||||
|
||||
// Is it an inner class being accessed?
|
||||
String qualified = findQualifiedName(typeImage, fileScope.getQualifiedTypeNames().keySet());
|
||||
if (qualified != null) {
|
||||
return qualified;
|
||||
}
|
||||
|
||||
// Is it an explicit import?
|
||||
qualified = findQualifiedName(typeImage, fileScope.getExplicitImports());
|
||||
if (qualified != null) {
|
||||
return qualified;
|
||||
}
|
||||
|
||||
return typeImage;
|
||||
}
|
||||
|
||||
private String findQualifiedName(String typeImage, Set<String> candidates) {
|
||||
int nameLength = typeImage.length();
|
||||
|
||||
for (String qualified : qualifiedNames) {
|
||||
for (String qualified : candidates) {
|
||||
int fullLength = qualified.length();
|
||||
if (qualified.endsWith(typeImage)
|
||||
&& (fullLength == nameLength || qualified.charAt(fullLength - nameLength - 1) == '.')) {
|
||||
return qualified;
|
||||
}
|
||||
}
|
||||
return typeImage;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,6 @@
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -57,9 +56,9 @@ public class LocalScope extends AbstractJavaScope {
|
||||
DeclarationFinderFunction finder = new DeclarationFinderFunction(occurrence);
|
||||
Applier.apply(finder, getVariableDeclarations().keySet().iterator());
|
||||
if (finder.getDecl() != null) {
|
||||
result.add(finder.getDecl());
|
||||
return Collections.singleton(finder.getDecl());
|
||||
}
|
||||
return result;
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
@ -3,7 +3,7 @@
|
||||
*/
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -54,16 +54,15 @@ public class MethodScope extends AbstractJavaScope {
|
||||
}
|
||||
|
||||
public Set<NameDeclaration> findVariableHere(JavaNameOccurrence occurrence) {
|
||||
Set<NameDeclaration> result = new HashSet<>();
|
||||
if (occurrence.isThisOrSuper() || occurrence.isMethodOrConstructorInvocation()) {
|
||||
return result;
|
||||
return Collections.emptySet();
|
||||
}
|
||||
ImageFinderFunction finder = new ImageFinderFunction(occurrence.getImage());
|
||||
Applier.apply(finder, getVariableDeclarations().keySet().iterator());
|
||||
if (finder.getDecl() != null) {
|
||||
result.add(finder.getDecl());
|
||||
return Collections.singleton(finder.getDecl());
|
||||
}
|
||||
return result;
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
@ -14,12 +14,17 @@ import net.sourceforge.pmd.lang.symboltable.Scope;
|
||||
|
||||
public class OccurrenceFinder extends JavaParserVisitorAdapter {
|
||||
|
||||
// Maybe do some sort of State pattern thingy for when NameDeclaration
|
||||
// is empty/not empty?
|
||||
private final Set<NameDeclaration> declarations = new HashSet<>();
|
||||
|
||||
private final Set<NameDeclaration> additionalDeclarations = new HashSet<>();
|
||||
|
||||
public Object visit(ASTPrimaryExpression node, Object data) {
|
||||
NameFinder nameFinder = new NameFinder(node);
|
||||
|
||||
// Maybe do some sort of State pattern thingy for when NameDeclaration
|
||||
// is empty/not empty?
|
||||
Set<NameDeclaration> declarations = new HashSet<>();
|
||||
declarations.clear();
|
||||
additionalDeclarations.clear();
|
||||
|
||||
List<JavaNameOccurrence> names = nameFinder.getNames();
|
||||
for (JavaNameOccurrence occ : names) {
|
||||
@ -36,7 +41,6 @@ public class OccurrenceFinder extends JavaParserVisitorAdapter {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Set<NameDeclaration> additionalDeclarations = new HashSet<>();
|
||||
for (NameDeclaration decl : declarations) {
|
||||
// now we've got a scope we're starting with, so work from there
|
||||
Scope startingScope = decl.getScope();
|
||||
|
@ -3,10 +3,8 @@
|
||||
*/
|
||||
package net.sourceforge.pmd.lang.java.symboltable;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -113,13 +111,12 @@ public class SourceFileScope extends AbstractJavaScope {
|
||||
}
|
||||
|
||||
protected Set<NameDeclaration> findVariableHere(JavaNameOccurrence occ) {
|
||||
Set<NameDeclaration> result = new HashSet<>();
|
||||
ImageFinderFunction finder = new ImageFinderFunction(occ.getImage());
|
||||
Applier.apply(finder, getDeclarations().keySet().iterator());
|
||||
if (finder.getDecl() != null) {
|
||||
result.add(finder.getDecl());
|
||||
return Collections.singleton(finder.getDecl());
|
||||
}
|
||||
return result;
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,8 +129,13 @@ public class SourceFileScope extends AbstractJavaScope {
|
||||
}
|
||||
|
||||
private Map<String, Node> getSubTypes(String qualifyingName, Scope subType) {
|
||||
Map<String, Node> types = new HashMap<>();
|
||||
for (ClassNameDeclaration c : subType.getDeclarations(ClassNameDeclaration.class).keySet()) {
|
||||
Set<ClassNameDeclaration> classDeclarations = subType.getDeclarations(ClassNameDeclaration.class).keySet();
|
||||
if (classDeclarations.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, Node> types = new HashMap<>((int) (classDeclarations.size() / 0.75f) + 1);
|
||||
for (ClassNameDeclaration c : classDeclarations) {
|
||||
String typeName = c.getName();
|
||||
if (qualifyingName != null) {
|
||||
typeName = qualifyingName + "." + typeName;
|
||||
|
@ -206,7 +206,7 @@ public class TypeSet {
|
||||
* Resolver that uses the current package to resolve a simple class name.
|
||||
*/
|
||||
public static class CurrentPackageResolver extends AbstractResolver {
|
||||
private String pkg;
|
||||
private final String pkg;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CurrentPackageResolver}
|
||||
@ -215,11 +215,19 @@ public class TypeSet {
|
||||
*/
|
||||
public CurrentPackageResolver(PMDASMClassLoader pmdClassLoader, String pkg) {
|
||||
super(pmdClassLoader);
|
||||
this.pkg = pkg;
|
||||
if (pkg == null) {
|
||||
this.pkg = null;
|
||||
} else {
|
||||
this.pkg = pkg + ".";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> resolve(String name) throws ClassNotFoundException {
|
||||
if (name == null) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
|
||||
final String fqName = qualifyName(name);
|
||||
final Class<?> c = resolveMaybeInner(fqName, fqName);
|
||||
|
||||
@ -240,7 +248,11 @@ public class TypeSet {
|
||||
return name;
|
||||
}
|
||||
|
||||
return pkg + '.' + name;
|
||||
/*
|
||||
* String.concat is bad in general, but for simple 2 string concatenation, it's the fastest
|
||||
* See http://www.rationaljava.com/2015/02/the-optimum-method-to-concatenate.html
|
||||
*/
|
||||
return pkg.concat(name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,7 +287,11 @@ public class TypeSet {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
clazz = pmdClassLoader.loadClass("java.lang." + name);
|
||||
/*
|
||||
* String.concat is bad in general, but for simple 2 string concatenation, it's the fastest
|
||||
* See http://www.rationaljava.com/2015/02/the-optimum-method-to-concatenate.html
|
||||
*/
|
||||
clazz = pmdClassLoader.loadClass("java.lang.".concat(name));
|
||||
CLASS_CACHE.putIfAbsent(name, clazz);
|
||||
|
||||
return clazz;
|
||||
@ -283,7 +299,11 @@ public class TypeSet {
|
||||
|
||||
@Override
|
||||
public boolean couldResolve(String name) {
|
||||
return super.couldResolve("java.lang." + name);
|
||||
/*
|
||||
* String.concat is bad in general, but for simple 2 string concatenation, it's the fastest
|
||||
* See http://www.rationaljava.com/2015/02/the-optimum-method-to-concatenate.html
|
||||
*/
|
||||
return super.couldResolve("java.lang.".concat(name));
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user