Skip to content

Commit

Permalink
Fixed formal typer parameter infer from variable declaration statement
Browse files Browse the repository at this point in the history
  • Loading branch information
diptopol committed Jun 28, 2022
1 parent dba2ff3 commit 6ac5377
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 50 deletions.
126 changes: 76 additions & 50 deletions src/main/java/ca/concordia/jaranalyzer/util/InferenceUtility.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ public static List<MethodInfo> getEligibleMethodInfoList(Set<Artifact> dependent
importStatementList, variableNameMap, expression, owningClassInfo);
}

TypeInfo returnTypeInfo = getReturnParameterizedTypeInfo(methodInvocation, variableNameMap);

TypeInferenceFluentAPI.Criteria searchCriteria = TypeInferenceFluentAPI.getInstance()
.new Criteria(dependentArtifactSet, javaVersion,
importStatementList, methodName, numberOfParameters)
Expand All @@ -94,8 +96,8 @@ public static List<MethodInfo> getEligibleMethodInfoList(Set<Artifact> dependent
* Order of transformTypeInfoRepresentation and conversionToVarargsMethodArgument matters. since we are
* converting last argument array type to vararg.
*/
transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList,
owningClassInfo, methodInfoList, argumentTypeInfoList, typeArgumentTypeInfoList, invokerClassTypeInfo);
transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList, owningClassInfo,
methodInfoList, argumentTypeInfoList, typeArgumentTypeInfoList, invokerClassTypeInfo, returnTypeInfo);
conversionToVarargsMethodArgument(methodInfoList);

return methodInfoList;
Expand Down Expand Up @@ -139,7 +141,7 @@ public static List<MethodInfo> getEligibleMethodInfoList(Set<Artifact> dependent
* converting last argument array type to vararg.
*/
transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList,
owningClassInfo, methodInfoList, argumentTypeInfoList, typeArgumentTypeInfoList, null);
owningClassInfo, methodInfoList, argumentTypeInfoList, typeArgumentTypeInfoList, null, null);
conversionToVarargsMethodArgument(methodInfoList);

return methodInfoList;
Expand All @@ -164,36 +166,10 @@ public static List<MethodInfo> getEligibleMethodInfoList(Set<Artifact> dependent
importStatementList, typeArgumentList, owningClassInfo);

Type type = classInstanceCreation.getType();
TypeInfo invokerClassTypeInfo = null;
TypeInfo returnTypeInfo = null;

if (type.isParameterizedType() && ((ParameterizedType) type).typeArguments().isEmpty()) {
VariableDeclarationStatement variableDeclarationStatement
= (VariableDeclarationStatement) InferenceUtility.getClosestASTNode(classInstanceCreation, VariableDeclarationStatement.class);

if (Objects.nonNull(variableDeclarationStatement)) {
Type returnType = variableDeclarationStatement.getType();

if (returnType.isParameterizedType()) {
ParameterizedType parameterizedReturnType = (ParameterizedType) returnType;

if (!parameterizedReturnType.typeArguments().isEmpty()) {
List<Type> returnTypeArgumentList = parameterizedReturnType.typeArguments();

List<TypeInfo> returnTypeInfoArgumentList =
getTypeInfoList(dependentArtifactSet, javaVersion, importStatementList,
returnTypeArgumentList, owningClassInfo);

invokerClassTypeInfo = InferenceUtility.getTypeInfo(dependentArtifactSet, javaVersion,
importStatementList, type, owningClassInfo);

assert invokerClassTypeInfo.isParameterizedTypeInfo();

ParameterizedTypeInfo parameterizedTypeInfo = (ParameterizedTypeInfo) invokerClassTypeInfo;
parameterizedTypeInfo.setParameterized(true);
parameterizedTypeInfo.setTypeArgumentList(returnTypeInfoArgumentList);
}
}
}
returnTypeInfo = getReturnParameterizedTypeInfo(classInstanceCreation, variableNameMap);
}

TypeInferenceFluentAPI.Criteria searchCriteria = TypeInferenceFluentAPI.getInstance()
Expand All @@ -208,7 +184,7 @@ public static List<MethodInfo> getEligibleMethodInfoList(Set<Artifact> dependent
List<MethodInfo> methodInfoList = searchCriteria.getMethodList();

InferenceUtility.transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList,
owningClassInfo, methodInfoList, argumentTypeInfoList, typeArgumentTypeInfoList, invokerClassTypeInfo);
owningClassInfo, methodInfoList, argumentTypeInfoList, typeArgumentTypeInfoList, null, returnTypeInfo);
conversionToVarargsMethodArgument(methodInfoList);

return methodInfoList;
Expand Down Expand Up @@ -258,8 +234,8 @@ public static List<MethodInfo> getEligibleMethodInfoList(Set<Artifact> dependent
* Order of transformTypeInfoRepresentation and conversionToVarargsMethodArgument matters. since we are
* converting last argument array type to vararg.
*/
transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList,
owningClassInfo, methodInfoList, Collections.emptyList(), typeArgumentTypeInfoList, invokerClassTypeInfo);
transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList, owningClassInfo,
methodInfoList, Collections.emptyList(), typeArgumentTypeInfoList, invokerClassTypeInfo, null);
conversionToVarargsMethodArgument(methodInfoList);

return methodInfoList;
Expand Down Expand Up @@ -299,8 +275,8 @@ public static List<MethodInfo> getEligibleMethodInfoList(Set<Artifact> dependent
* Order of transformTypeInfoRepresentation and conversionToVarargsMethodArgument matters. since we are
* converting last argument array type to vararg.
*/
transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList,
owningClassInfo, methodInfoList, Collections.emptyList(), typeArgumentTypeInfoList, null);
transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList, owningClassInfo,
methodInfoList, Collections.emptyList(), typeArgumentTypeInfoList, null, null);
conversionToVarargsMethodArgument(methodInfoList);

return methodInfoList;
Expand Down Expand Up @@ -341,8 +317,8 @@ public static List<MethodInfo> getEligibleMethodInfoList(Set<Artifact> dependent
* Order of transformTypeInfoRepresentation and conversionToVarargsMethodArgument matters. since we are
* converting last argument array type to vararg.
*/
transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList,
owningClassInfo, methodInfoList, Collections.emptyList(), typeArgumentTypeInfoList, null);
transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList, owningClassInfo,
methodInfoList, Collections.emptyList(), typeArgumentTypeInfoList, null, null);
conversionToVarargsMethodArgument(methodInfoList);

return methodInfoList;
Expand Down Expand Up @@ -386,8 +362,8 @@ public static List<MethodInfo> getEligibleMethodInfoList(Set<Artifact> dependent
* Order of transformTypeInfoRepresentation and conversionToVarargsMethodArgument matters. since we are
* converting last argument array type to vararg.
*/
transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList,
owningClassInfo, methodInfoList, Collections.emptyList(), typeArgumentTypeInfoList, invokerClassTypeInfo);
transformTypeInfoRepresentation(dependentArtifactSet, javaVersion, importStatementList, owningClassInfo,
methodInfoList, Collections.emptyList(), typeArgumentTypeInfoList, invokerClassTypeInfo, null);
conversionToVarargsMethodArgument(methodInfoList);

return methodInfoList;
Expand Down Expand Up @@ -794,7 +770,7 @@ public static TypeInfo getTypeInfoFromExpression(Set<Artifact> dependentArtifact

if (expression instanceof QualifiedName) {
String firstPart = name.substring(0, name.indexOf("."));
VariableDeclarationDto selected = getClassNameFromVariableMap(firstPart, expression, variableNameMap);
VariableDeclarationDto selected = getVariableDeclarationDtoFromVariableMap(firstPart, expression, variableNameMap);
String className = selected != null ? selected.getTypeInfo().getQualifiedClassName() : null;

if (className != null) {
Expand All @@ -811,7 +787,7 @@ public static TypeInfo getTypeInfoFromExpression(Set<Artifact> dependentArtifact
owningClassInfo);
}
} else if (expression instanceof SimpleName) {
VariableDeclarationDto selected = getClassNameFromVariableMap(name, expression, variableNameMap);
VariableDeclarationDto selected = getVariableDeclarationDtoFromVariableMap(name, expression, variableNameMap);
TypeInfo classTypeInfo = selected != null ? selected.getTypeInfo() : null;

if (Objects.nonNull(classTypeInfo)) {
Expand Down Expand Up @@ -1198,15 +1174,17 @@ public static void transformTypeInfoRepresentation(Set<Artifact> dependentArtifa
List<MethodInfo> methodInfoList,
List<TypeInfo> argumentTypeInfoList,
List<TypeInfo> typeArgumentTypeInfoList,
TypeInfo invokerTypeInfo) {
TypeInfo invokerTypeInfo,
TypeInfo returnTypeInfo) {

for (MethodInfo methodInfo : methodInfoList) {
convertParameterizedTypeIfRequired(dependentArtifactSet, javaVersion, importStatementList,
owningClassInfo, methodInfo);

Map<String, TypeInfo> replacedTypeInfoMap = new HashMap<>();
invokerTypeInfo = getOriginalInvoker(invokerTypeInfo, methodInfo, owningClassInfo);
Map<String, TypeInfo> formalTypeParameterMap = getInferredFormalTypeParameterMap(invokerTypeInfo, methodInfo, argumentTypeInfoList, typeArgumentTypeInfoList);
Map<String, TypeInfo> formalTypeParameterMap = getInferredFormalTypeParameterMap(invokerTypeInfo,
returnTypeInfo, methodInfo, argumentTypeInfoList, typeArgumentTypeInfoList);

if (Objects.nonNull(owningClassInfo) && Objects.nonNull(invokerTypeInfo)
&& owningClassInfo.getQualifiedClassNameSetInHierarchy().get(0).contains(invokerTypeInfo.getQualifiedClassName())) {
Expand Down Expand Up @@ -1272,6 +1250,31 @@ public static List<String> getInnerClassQNameList(AbstractTypeDeclaration abstra
}


private static TypeInfo getReturnParameterizedTypeInfo(ASTNode methodNode,
Map<String, Set<VariableDeclarationDto>> variableNameMap) {
VariableDeclarationStatement variableDeclarationStatement
= (VariableDeclarationStatement) InferenceUtility.getClosestASTNode(methodNode, VariableDeclarationStatement.class);

if (Objects.nonNull(variableDeclarationStatement)) {
List<VariableDeclarationFragment> fragmentList = variableDeclarationStatement.fragments();

if (!fragmentList.isEmpty()) {
VariableDeclarationFragment fragment = fragmentList.get(0);
String variableName = fragment.getName().getFullyQualifiedName();

VariableDeclarationDto variableDeclarationDto =
getVariableDeclarationDtoFromVariableMap(variableName, fragment.getStartPosition(), variableNameMap);

if (Objects.nonNull(variableDeclarationDto)) {
return variableDeclarationDto.getTypeInfo();
}
}
}

return null;
}


/*
* There are scenarios when parameterized type is called without type arguments in method signature.
* (e.g., public Stack getCurrentSeriesPoints() {})
Expand Down Expand Up @@ -1373,6 +1376,7 @@ private static TypeInfo getOriginalInvoker(TypeInfo invokerTypeInfo,
}

private static Map<String, TypeInfo> getInferredFormalTypeParameterMap(TypeInfo invokerTypeInfo,
TypeInfo returnTypeInfo,
MethodInfo methodInfo,
List<TypeInfo> argumentTypeInfoList,
List<TypeInfo> typeArgumentTypeInfoList) {
Expand All @@ -1393,6 +1397,23 @@ private static Map<String, TypeInfo> getInferredFormalTypeParameterMap(TypeInfo
);
}

if (Objects.nonNull(returnTypeInfo)
&& returnTypeInfo.isParameterizedTypeInfo()
&& ((ParameterizedTypeInfo) returnTypeInfo).isParameterized()
&& returnTypeInfo.getQualifiedClassName().equals(methodInfo.getReturnTypeInfo().getQualifiedClassName())) {
ParameterizedTypeInfo parameterizedTypeInfo = (ParameterizedTypeInfo) returnTypeInfo;

for (TypeInfo typeArgumentInfo : parameterizedTypeInfo.getTypeArgumentList()) {
if (typeArgumentInfo.isFormalTypeParameterInfo()) {
FormalTypeParameterInfo formalTypeParameterInfo = (FormalTypeParameterInfo) typeArgumentInfo;

if (!inferredTypeInfoMap.containsKey(formalTypeParameterInfo.getTypeParameter())) {
inferredTypeInfoMap.put(formalTypeParameterInfo.getTypeParameter(), formalTypeParameterInfo.getBaseTypeInfo());
}
}
}
}

if (!typeArgumentTypeInfoList.isEmpty()) {
List<TypeInfo> formalTypeParameterList = methodInfo.getFormalTypeParameterList();

Expand Down Expand Up @@ -1801,12 +1822,17 @@ private static VariableDeclarationDto getVariableDeclarationDto(Set<Artifact> de
}
}

private static VariableDeclarationDto getClassNameFromVariableMap(String name,
Expression expression,
Map<String, Set<VariableDeclarationDto>> variableNameMap) {
if (variableNameMap.containsKey(name)) {
int position = expression.getParent().getStartPosition();
Set<VariableDeclarationDto> variableDeclarationDtoSet = variableNameMap.get(name);
private static VariableDeclarationDto getVariableDeclarationDtoFromVariableMap(String variableName,
Expression expression,
Map<String, Set<VariableDeclarationDto>> variableNameMap) {
return getVariableDeclarationDtoFromVariableMap(variableName, expression.getParent().getStartPosition(), variableNameMap);
}

private static VariableDeclarationDto getVariableDeclarationDtoFromVariableMap(String variableName,
int position,
Map<String, Set<VariableDeclarationDto>> variableNameMap) {
if (variableNameMap.containsKey(variableName)) {
Set<VariableDeclarationDto> variableDeclarationDtoSet = variableNameMap.get(variableName);
List<VariableDeclarationDto> selectedVariableDeclarationDto = new ArrayList<>();

for (VariableDeclarationDto vd : variableDeclarationDtoSet) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,26 @@ public boolean visit(MethodInvocation methodInvocation) {
});
}

@Test
public void testFormalTypeParameterInferFromVariableDeclarationStatement() {
String filePath = "testProjectDirectory/guava/guava/guava/src/com/google/common/util/concurrent/MoreExecutors.java";
CompilationUnit compilationUnit = TestUtils.getCompilationUnitFromFile(filePath);
compilationUnit.accept(new ASTVisitor() {
@Override
public boolean visit(MethodInvocation methodInvocation) {
if (methodInvocation.toString().startsWith("TrustedListenableFutureTask.create(command,")) {
MethodInfo methodInfo = TypeInferenceV2API.getMethodInfo(jarInformationSet, javaVersion, methodInvocation);

assert ("com.google.common.util.concurrent.TrustedListenableFutureTask" +
"::static com.google.common.util.concurrent.TrustedListenableFutureTask create(java.lang.Runnable," +
" java.lang.Void)").equals(methodInfo.toString());
}

return true;
}
});
}

private static void loadTestProjectDirectory(String projectName, String projectUrl, String commitId) {
Path projectDirectory = Paths.get("testProjectDirectory").resolve(projectName);

Expand Down

0 comments on commit 6ac5377

Please sign in to comment.