private static JavaType elementType(JavaType javaType) { if(javaType.isArray()) { return elementType(((ArrayJavaType) javaType).elementType); } return javaType; } }
private static JavaType elementType(JavaType javaType) { if(javaType.isArray()) { return elementType(((ArrayJavaType) javaType).elementType); } return javaType; } }
private JavaType substituteInArrayType(ArrayJavaType arrayType, TypeSubstitution substitution) { JavaType rootElementType = arrayType.elementType; int nbDimensions = 1; while (rootElementType.isArray()) { rootElementType = ((ArrayJavaType) rootElementType).elementType; nbDimensions++; } JavaType substitutedType = applySubstitution(rootElementType, substitution); if (substitutedType != rootElementType) { // FIXME SONARJAVA-1574 a new array type should not be created but reused if already existing for the current element type for (int i = 0; i < nbDimensions; i++) { substitutedType = new ArrayJavaType(substitutedType, symbols.arrayClass); } return substitutedType; } return arrayType; }
private Resolution lookupInScope(Env env, JavaType callSite, JavaType site, String name, List<JavaType> argTypes, List<JavaType> typeParams, boolean looseInvocation, boolean varArity, Scope scope, Resolution bestFound) { Resolution bestSoFar = bestFound; // look in site members for (JavaSymbol symbol : scope.lookup(name)) { if (symbol.kind == JavaSymbol.MTH) { boolean diffArity = varArity || (!((JavaSymbol.MethodJavaSymbol) symbol).isVarArgs()) || (argTypes.size() == ((JavaSymbol.MethodJavaSymbol) symbol).parameterTypes().size() && argTypes.get(argTypes.size() -1 ).isArray()); if(diffArity) { Resolution best = selectBest(env, site, callSite, argTypes, typeParams, symbol, bestSoFar, looseInvocation); if (best.symbol == symbol) { bestSoFar = best; } } } } return bestSoFar; }
private Resolution lookupInScope(Env env, JavaType callSite, JavaType site, String name, List<JavaType> argTypes, List<JavaType> typeParams, boolean looseInvocation, boolean varArity, Scope scope, Resolution bestFound) { Resolution bestSoFar = bestFound; // look in site members for (JavaSymbol symbol : scope.lookup(name)) { if (symbol.kind == JavaSymbol.MTH) { boolean diffArity = varArity || (!((JavaSymbol.MethodJavaSymbol) symbol).isVarArgs()) || (argTypes.size() == ((JavaSymbol.MethodJavaSymbol) symbol).parameterTypes().size() && argTypes.get(argTypes.size() -1 ).isArray()); if(diffArity) { Resolution best = selectBest(env, site, callSite, argTypes, typeParams, symbol, bestSoFar, looseInvocation); if (best.symbol == symbol) { bestSoFar = best; } } } } return bestSoFar; }
private JavaType substituteInArrayType(ArrayJavaType arrayType, TypeSubstitution substitution) { JavaType rootElementType = arrayType.elementType; int nbDimensions = 1; while (rootElementType.isArray()) { rootElementType = ((ArrayJavaType) rootElementType).elementType; nbDimensions++; } JavaType substitutedType = applySubstitution(rootElementType, substitution); if (substitutedType != rootElementType) { // FIXME SONARJAVA-1574 a new array type should not be created but reused if already existing for the current element type for (int i = 0; i < nbDimensions; i++) { substitutedType = new ArrayJavaType(substitutedType, symbols.arrayClass); } return substitutedType; } return arrayType; }
/** * @return true, if signature of m1 is more specific than signature of m2 */ private boolean isSignatureMoreSpecific(JavaSymbol m1, JavaSymbol m2, List<JavaType> argTypes, TypeSubstitution m1Substitution, TypeSubstitution m2Substitution) { List<JavaType> m1ArgTypes = ((MethodJavaType) m1.type).argTypes; List<JavaType> m2ArgTypes = ((MethodJavaType) m2.type).argTypes; JavaSymbol.MethodJavaSymbol methodJavaSymbol = (JavaSymbol.MethodJavaSymbol) m1; boolean m1VarArity = methodJavaSymbol.isVarArgs(); boolean m2VarArity = ((JavaSymbol.MethodJavaSymbol) m2).isVarArgs(); if (m1VarArity != m2VarArity) { // last arg is an array boolean lastArgIsArray = !argTypes.isEmpty() && argTypes.get(argTypes.size() -1).isArray() && (argTypes.size() == m2ArgTypes.size() || argTypes.size() == m1ArgTypes.size()); // general case : prefer strict arity invocation over varArity, so if m2 is variadic, m1 is most specific, but not if last arg of invocation is an array return lastArgIsArray ^ m2VarArity; } if (m1VarArity) { m1ArgTypes = expandVarArgsToFitSize(m1ArgTypes, m2ArgTypes.size()); } if(!hasCompatibleArity(m1ArgTypes.size(), m2ArgTypes.size(), m2VarArity)) { return false; } m1ArgTypes = typeSubstitutionSolver.applySubstitutionToFormalParameters(m1ArgTypes, m1Substitution); m2ArgTypes = typeSubstitutionSolver.applySubstitutionToFormalParameters(m2ArgTypes, m2Substitution); return isArgumentsAcceptable(m1ArgTypes, m2ArgTypes, m2VarArity, true); }
@CheckForNull private static JavaType getCollectionItemType(ExpressionTree expression) { JavaType expressionType = (JavaType) expression.symbolType(); if (expressionType.isSubtypeOf("java.util.Collection") && !expressionType.isParameterized()) { // Ignoring raw collections (too many FP) return null; } if (expressionType.isArray()) { return ((ArrayJavaType) expressionType).elementType(); } else if(expressionType.isClass()) { ClassJavaType clazz = (ClassJavaType) expressionType; return clazz.superTypes() .stream() .filter(t -> t.is("java.lang.Iterable") && t.isParameterized()) .findFirst() .map(iter -> { ParametrizedTypeJavaType ptype = (ParametrizedTypeJavaType) iter; return ptype.substitution(ptype.typeParameters().get(0)); }).orElse(null); } return null; }
@CheckForNull private static JavaType getCollectionItemType(ExpressionTree expression) { JavaType expressionType = (JavaType) expression.symbolType(); if (expressionType.isSubtypeOf("java.util.Collection") && !expressionType.isParameterized()) { // Ignoring raw collections (too many FP) return null; } if (expressionType.isArray()) { return ((ArrayJavaType) expressionType).elementType(); } else if(expressionType.isClass()) { ClassJavaType clazz = (ClassJavaType) expressionType; return clazz.superTypes() .stream() .filter(t -> t.is("java.lang.Iterable") && t.isParameterized()) .findFirst() .map(iter -> { ParametrizedTypeJavaType ptype = (ParametrizedTypeJavaType) iter; return ptype.substitution(ptype.typeParameters().get(0)); }).orElse(null); } return null; }
private TypeSubstitution inferTypeSubstitutionInArrayType(MethodJavaSymbol method, TypeSubstitution substitution, ArrayJavaType formalType, JavaType argType, boolean variableArity, List<JavaType> remainingArgTypes) { JavaType newArgType = null; if (argType.isArray()) { newArgType = ((ArrayJavaType) argType).elementType; } else if (variableArity) { newArgType = (JavaType) leastUpperBound.leastUpperBound(mapToBoxedSet(remainingArgTypes)); } if (newArgType != null) { TypeSubstitution newSubstitution = inferTypeSubstitution(method, substitution, formalType.elementType, newArgType, variableArity, remainingArgTypes); return mergeTypeSubstitutions(substitution, newSubstitution); } return substitution; }
private void handleNewArray(MethodReferenceTree methodReferenceTree, JavaType methodRefType, JavaType samReturnType) { JavaType expressionType = getType(methodReferenceTree.expression()); if (expressionType != null && expressionType.isArray() && "new".equals(methodReferenceTree.method().name())) { JavaType capturedReturnType = resolve.resolveTypeSubstitution(samReturnType, methodRefType); refineType((MethodReferenceTreeImpl) methodReferenceTree, methodRefType, capturedReturnType, expressionType); } }
private void handleNewArray(MethodReferenceTree methodReferenceTree, JavaType methodRefType, JavaType samReturnType) { JavaType expressionType = getType(methodReferenceTree.expression()); if (expressionType != null && expressionType.isArray() && "new".equals(methodReferenceTree.method().name())) { JavaType capturedReturnType = resolve.resolveTypeSubstitution(samReturnType, methodRefType); refineType((MethodReferenceTreeImpl) methodReferenceTree, methodRefType, capturedReturnType, expressionType); } }
private TypeSubstitution inferTypeSubstitutionInArrayType(MethodJavaSymbol method, TypeSubstitution substitution, ArrayJavaType formalType, JavaType argType, boolean variableArity, List<JavaType> remainingArgTypes) { JavaType newArgType = null; if (argType.isArray()) { newArgType = ((ArrayJavaType) argType).elementType; } else if (variableArity) { newArgType = (JavaType) leastUpperBound.leastUpperBound(mapToBoxedSet(remainingArgTypes)); } if (newArgType != null) { TypeSubstitution newSubstitution = inferTypeSubstitution(method, substitution, formalType.elementType, newArgType, variableArity, remainingArgTypes); return mergeTypeSubstitutions(substitution, newSubstitution); } return substitution; }
private static boolean isReturnTypeCompletelySubstituted(JavaType resultType, List<TypeVariableJavaType> typeVariables){ if(typeVariables.contains(resultType)) { return false; } if(resultType.isArray()) { return isReturnTypeCompletelySubstituted(((ArrayJavaType) resultType).elementType, typeVariables); } if(resultType.isTagged(JavaType.WILDCARD)) { return isReturnTypeCompletelySubstituted(((WildCardType) resultType).bound, typeVariables); } if (resultType.isParameterized()) { for (JavaType substitutedType : ((ParametrizedTypeJavaType) resultType).typeSubstitution.substitutedTypes()) { if(!isReturnTypeCompletelySubstituted(substitutedType, typeVariables)) { return false; } } } return true; }
private static boolean isReturnTypeCompletelySubstituted(JavaType resultType, List<TypeVariableJavaType> typeVariables){ if(typeVariables.contains(resultType)) { return false; } if(resultType.isArray()) { return isReturnTypeCompletelySubstituted(((ArrayJavaType) resultType).elementType, typeVariables); } if(resultType.isTagged(JavaType.WILDCARD)) { return isReturnTypeCompletelySubstituted(((WildCardType) resultType).bound, typeVariables); } if (resultType.isParameterized()) { for (JavaType substitutedType : ((ParametrizedTypeJavaType) resultType).typeSubstitution.substitutedTypes()) { if(!isReturnTypeCompletelySubstituted(substitutedType, typeVariables)) { return false; } } } return true; }
private TypeSubstitution inferTypeSubstitution(MethodJavaSymbol method, TypeSubstitution substitution, JavaType formalType, JavaType argumentType, boolean variableArity, List<JavaType> remainingArgTypes) { if(handledFormals.get(formalType).contains(argumentType)) { return substitution; } JavaType argType = argumentType; if (argType.isTagged(JavaType.DEFERRED)) { argType = ((DeferredType) argType).getUninferedType(); } handledFormals.put(formalType, argType); TypeSubstitution result = substitution; if (formalType.isTagged(JavaType.TYPEVAR)) { result = inferTypeSubstitutionInTypeVariable(method, substitution, (TypeVariableJavaType) formalType, argType, variableArity, remainingArgTypes); } else if (formalType.isArray()) { result = inferTypeSubstitutionInArrayType(method, substitution, (ArrayJavaType) formalType, argType, variableArity, remainingArgTypes); } else if (formalType.isParameterized()) { result = inferTypeSubstitutionInParameterizedType(method, substitution, (ParametrizedTypeJavaType) formalType, argType, variableArity, remainingArgTypes); } else if (formalType.isTagged(JavaType.WILDCARD)) { result = inferTypeSubstitutionInWildcardType(method, substitution, (WildCardType) formalType, argType, variableArity, remainingArgTypes); } else { // nothing to infer for simple class types or primitive types } return result; }
JavaType applySubstitution(JavaType type, TypeSubstitution substitution) { JavaType substitutedType = substitution.substitutedType(type); if (substitutedType != null) { return substitutedType; } if (type.isTagged(JavaType.TYPEVAR)) { return substituteInTypeVar((TypeVariableJavaType) type, substitution); } if (type.isParameterized()) { return substituteInParametrizedType((ParametrizedTypeJavaType) type, substitution); } if (type.isTagged(JavaType.WILDCARD)) { return substituteInWildCardType((WildCardType) type, substitution); } if (type.isArray()) { return substituteInArrayType((ArrayJavaType) type, substitution); } return type; }
JavaType applySubstitution(JavaType type, TypeSubstitution substitution) { JavaType substitutedType = substitution.substitutedType(type); if (substitutedType != null) { return substitutedType; } if (type.isTagged(JavaType.TYPEVAR)) { return substituteInTypeVar((TypeVariableJavaType) type, substitution); } if (type.isParameterized()) { return substituteInParametrizedType((ParametrizedTypeJavaType) type, substitution); } if (type.isTagged(JavaType.WILDCARD)) { return substituteInWildCardType((WildCardType) type, substitution); } if (type.isArray()) { return substituteInArrayType((ArrayJavaType) type, substitution); } return type; }
private boolean isAcceptableType(JavaType arg, JavaType formal, boolean autoboxing) { if(arg.isTagged(JavaType.DEFERRED)) { return isAcceptableDeferredType((DeferredType) arg, formal); } if(formal.isTagged(JavaType.TYPEVAR) && !arg.isTagged(JavaType.TYPEVAR)) { return subtypeOfTypeVar(arg, (TypeVariableJavaType) formal); } if (formal.isArray() && arg.isArray()) { return isAcceptableType(((ArrayJavaType) arg).elementType(), ((ArrayJavaType) formal).elementType(), autoboxing); } if (arg.isParameterized() || formal.isParameterized() || isWilcardType(arg) || isWilcardType(formal)) { return callWithRawType(arg, formal) || types.isSubtype(arg, formal) || isAcceptableByAutoboxing(arg, formal.erasure()); } // fall back to behavior based on erasure return types.isSubtype(arg.erasure(), formal.erasure()) || (autoboxing && isAcceptableByAutoboxing(arg, formal.erasure())); }
private boolean isAcceptableType(JavaType arg, JavaType formal, boolean autoboxing) { if(arg.isTagged(JavaType.DEFERRED)) { return isAcceptableDeferredType((DeferredType) arg, formal); } if(formal.isTagged(JavaType.TYPEVAR) && !arg.isTagged(JavaType.TYPEVAR)) { return subtypeOfTypeVar(arg, (TypeVariableJavaType) formal); } if (formal.isArray() && arg.isArray()) { return isAcceptableType(((ArrayJavaType) arg).elementType(), ((ArrayJavaType) formal).elementType(), autoboxing); } if (arg.isParameterized() || formal.isParameterized() || isWilcardType(arg) || isWilcardType(formal)) { return callWithRawType(arg, formal) || types.isSubtype(arg, formal) || isAcceptableByAutoboxing(arg, formal.erasure()); } // fall back to behavior based on erasure return types.isSubtype(arg.erasure(), formal.erasure()) || (autoboxing && isAcceptableByAutoboxing(arg, formal.erasure())); }