Java, typeres: add static method resolution
This commit is contained in:
@ -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()) {
|
||||
|
@ -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));
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Reference in New Issue
Block a user