Java, typeres: add static method resolution

This commit is contained in:
Bendegúz Nagy
2017-07-10 19:15:20 +02:00
parent 4fb214cf64
commit 2146a077eb
4 changed files with 72 additions and 48 deletions

View File

@ -101,7 +101,8 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
private static final Map<String, String> JAVA_LANG;
private Map<String, JavaTypeDefinition> staticFieldImageToTypeDef;
private List<String> staticFieldImportOnDemand;
private Map<String, List<JavaTypeDefinition>> staticNamesToClasses;
private List<JavaTypeDefinition> importOnDemandStaticClasses;
private ASTCompilationUnit currentAcu;
static {
@ -189,7 +190,8 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
importedOnDemand = new ArrayList<>();
importedClasses = new HashMap<>();
staticFieldImageToTypeDef = new HashMap<>();
staticFieldImportOnDemand = new ArrayList<>();
staticNamesToClasses = new HashMap<>();
importOnDemandStaticClasses = new ArrayList<>();
// TODO: this fails to account for multiple classes in the same file
// later classes (in the ACU) won't have their Nested classes registered
@ -409,21 +411,19 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
JavaTypeDefinition previousType;
// TODO: static method invocation
if (dotSplitImage.length == 1 && astArguments != null) { // method
if (node.getType() != null) { // static field or method
previousType = JavaTypeDefinition.forClass(node.getType());
} else { // non-static field or method
if (dotSplitImage.length == 1 && astArguments != null) { // method
List<MethodType> methods = getLocalApplicableMethods(node, dotSplitImage[0], null,
methodArgsArity, accessingClass);
List<MethodType> methods = getLocalApplicableMethods(node, dotSplitImage[0], null,
methodArgsArity, accessingClass);
previousType = getBestMethodReturnType(methods, astArgumentList, null);
startIndex = 1;
} else { // field
if (node.getType() != null) { // the searchNodeNameForClass above found a class in the image -> static field
previousType = JavaTypeDefinition.forClass(node.getType());
} else { // non-static field access
previousType = getTypeDefinitionOfVariableFromScope(node.getScope(), dotSplitImage[0], accessingClass);
startIndex = 1; // first element's type in dotSplitImage has already been resolved
previousType = getBestMethodReturnType(methods, astArgumentList, null);
} else { // field
previousType = getTypeDefinitionOfVariableFromScope(node.getScope(), dotSplitImage[0],
accessingClass);
}
startIndex = 1; // first element's type in dotSplitImage has already been resolved
}
// TODO: remove this if branch, it's only purpose is to make JUnitAssertionsShouldIncludeMessage's tests pass
@ -486,7 +486,37 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
argArity, accessingClass));
}
// TODO: search static methods
foundMethods.addAll(searchImportedStaticMethods(methodName, typeArguments, argArity, accessingClass));
return foundMethods;
}
private List<MethodType> searchImportedStaticMethods(String methodName,
List<JavaTypeDefinition> typeArguments,
int argArity,
Class<?> accessingClass) {
List<MethodType> foundMethods = new ArrayList<>();
// TODO: member methods must not be looked at in the code below
List<JavaTypeDefinition> explicitImports = staticNamesToClasses.get(methodName);
if (explicitImports != null) {
for (JavaTypeDefinition anImport : explicitImports) {
foundMethods.addAll(getApplicableMethods(anImport, methodName, typeArguments, argArity,
accessingClass));
}
}
if (!foundMethods.isEmpty()) {
// if we found an method by explicit imports, on deamand imports mustn't be searched, because
// explicit imports shadow them by name, regardless of method parameters
return foundMethods;
}
for (JavaTypeDefinition anOnDemandImport : importOnDemandStaticClasses) {
foundMethods.addAll(getApplicableMethods(anOnDemandImport, methodName, typeArguments, argArity,
accessingClass));
}
return foundMethods;
}
@ -605,10 +635,8 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
return staticFieldImageToTypeDef.get(fieldName);
}
for (String anOnDemandImport : staticFieldImportOnDemand) {
JavaTypeDefinition typeDef
= getFieldType(JavaTypeDefinition.forClass(loadClass(anOnDemandImport)), fieldName,
currentAcu.getType());
for (JavaTypeDefinition anOnDemandImport : importOnDemandStaticClasses) {
JavaTypeDefinition typeDef = getFieldType(anOnDemandImport, fieldName, currentAcu.getType());
if (typeDef != null) {
staticFieldImageToTypeDef.put(fieldName, typeDef);
return typeDef;
@ -1349,7 +1377,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
String strPackage = anImportDeclaration.getPackageName();
if (anImportDeclaration.isStatic()) {
if (anImportDeclaration.isImportOnDemand()) {
staticFieldImportOnDemand.add(strPackage);
importOnDemandStaticClasses.add(JavaTypeDefinition.forClass(loadClass(strPackage)));
} else { // not import on-demand
String strName = anImportDeclaration.getImportedName();
String fieldName = strName.substring(strName.lastIndexOf('.') + 1);
@ -1360,6 +1388,16 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
fieldName, currentAcu.getType());
staticFieldImageToTypeDef.put(fieldName, typeDef);
}
List<JavaTypeDefinition> typeList = staticNamesToClasses.get(fieldName);
if (typeList == null) {
typeList = new ArrayList<>();
}
typeList.add(JavaTypeDefinition.forClass(staticClassWithField));
staticNamesToClasses.put(fieldName, typeList);
}
} else { // non-static
if (anImportDeclaration.isImportOnDemand()) {

View File

@ -4,8 +4,6 @@
package net.sourceforge.pmd.typeresolution;
import static net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticMembers.primitiveStaticMethod;
import static net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticMembers.staticInstanceMethod;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
@ -18,9 +16,6 @@ import java.util.Comparator;
import java.util.List;
import java.util.StringTokenizer;
import net.sourceforge.pmd.typeresolution.testdata.MethodStaticAccess;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticMembers;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticSuper;
import org.apache.commons.io.IOUtils;
import org.jaxen.JaxenException;
@ -80,6 +75,7 @@ import net.sourceforge.pmd.typeresolution.testdata.MethodFirstPhase;
import net.sourceforge.pmd.typeresolution.testdata.MethodMostSpecific;
import net.sourceforge.pmd.typeresolution.testdata.MethodPotentialApplicability;
import net.sourceforge.pmd.typeresolution.testdata.MethodSecondPhase;
import net.sourceforge.pmd.typeresolution.testdata.MethodStaticAccess;
import net.sourceforge.pmd.typeresolution.testdata.MethodThirdPhase;
import net.sourceforge.pmd.typeresolution.testdata.NestedAnonymousClass;
import net.sourceforge.pmd.typeresolution.testdata.Operators;
@ -88,6 +84,7 @@ import net.sourceforge.pmd.typeresolution.testdata.SuperExpression;
import net.sourceforge.pmd.typeresolution.testdata.ThisExpression;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.Converter;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.GenericClass;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticMembers;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassA;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassA2;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassB;
@ -1424,16 +1421,6 @@ public class ClassTypeResolverTest {
assertEquals(int.class, getChildType(expressions.get(index), 0));
assertEquals(int.class, getChildType(expressions.get(index++), 1));
// String a = primitiveStaticMethod();
assertEquals(String.class, expressions.get(index).getType());
assertEquals(String.class, getChildType(expressions.get(index), 0));
assertEquals(String.class, getChildType(expressions.get(index++), 1));
// double b = staticCharMethod();
assertEquals(double.class, expressions.get(index).getType());
assertEquals(double.class, getChildType(expressions.get(index), 0));
assertEquals(double.class, getChildType(expressions.get(index++), 1));
// String c = MethodStaticAccess.Nested.primitiveStaticMethod();
assertEquals(String.class, expressions.get(index).getType());
assertEquals(String.class, getChildType(expressions.get(index), 0));

View File

@ -1,18 +1,19 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.typeresolution.testdata;
import static net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticMembers.*;
import static net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticMembers.primitiveStaticMethod;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticMembers;
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticSuper;
import static net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticMembers.primitiveStaticMethod;
import static net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticMembers.*;
public class MethodStaticAccess {
public static double staticChar;
public static double staticCharMethod() {
return 0;
}
void foo() {
// static field import by explicit import
int a = primitiveStaticMethod();
@ -26,12 +27,6 @@ public class MethodStaticAccess {
public class Nested extends StaticSuper {
void bar() {
// import shadowed by inherited static
String a = primitiveStaticMethod();
// enclosing scope staticChar shadows imported static field
double b = staticCharMethod();
// qualified access
String c = MethodStaticAccess.Nested.primitiveStaticMethod();
}

View File

@ -1,3 +1,7 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.typeresolution.testdata.dummytypes;
public class StaticSuper {