public String toString() { return toString(true); }
protected static String prettyPrintMethodList(List<MethodNode> nodes) { StringBuilder sb = new StringBuilder("["); for (int i = 0, nodesSize = nodes.size(); i < nodesSize; i++) { final MethodNode node = nodes.get(i); sb.append(node.getReturnType().toString(false)); sb.append(" "); sb.append(node.getDeclaringClass().toString(false)); sb.append("#"); sb.append(toMethodParametersString(node.getName(), extractTypesFromParameters(node.getParameters()))); if (i < nodesSize - 1) sb.append(", "); } sb.append("]"); return sb.toString(); }
private void throwExceptionForNoStackElement(int size, ClassNode targetType, boolean coerce) { if (size>0) return; StringBuilder sb = new StringBuilder(); sb.append("Internal compiler error while compiling ").append(controller.getSourceUnit().getName()).append("\n"); MethodNode methodNode = controller.getMethodNode(); if (methodNode!=null) { sb.append("Method: "); sb.append(methodNode); sb.append("\n"); } ConstructorNode constructorNode = controller.getConstructorNode(); if (constructorNode!=null) { sb.append("Constructor: "); sb.append(methodNode); sb.append("\n"); } sb.append("Line ").append(controller.getLineNumber()).append(","); sb.append(" expecting ").append(coerce ? "coercion" : "casting").append(" to ").append(targetType.toString(false)); sb.append(" but operand stack is empty"); throw new ArrayIndexOutOfBoundsException(sb.toString()); }
public String toString(boolean showRedirect) { if (isArray()) { return componentType.toString(showRedirect)+"[]"; } StringBuilder ret = new StringBuilder(getName()); if (placeholder) ret = new StringBuilder(getUnresolvedName()); if (!placeholder && genericsTypes != null) { ret.append(" <"); for (int i = 0; i < genericsTypes.length; i++) { if (i != 0) ret.append(", "); GenericsType genericsType = genericsTypes[i]; ret.append(genericTypeAsString(genericsType)); } ret.append(">"); } if (redirect != null && showRedirect) { ret.append(" -> ").append(redirect().toString()); } return ret.toString(); }
static String prettyPrintType(ClassNode type) { if (type.isArray()) { return prettyPrintType(type.getComponentType()) + "[]"; } return type.toString(false); }
private boolean typeCheckMultipleAssignmentAndContinue(Expression leftExpression, Expression rightExpression) { // multiple assignment check if (!(leftExpression instanceof TupleExpression)) return true; if (!(rightExpression instanceof ListExpression)) { addStaticTypeError("Multiple assignments without list expressions on the right hand side are unsupported in static type checking mode", rightExpression); return false; } TupleExpression tuple = (TupleExpression) leftExpression; ListExpression list = (ListExpression) rightExpression; List<Expression> listExpressions = list.getExpressions(); List<Expression> tupleExpressions = tuple.getExpressions(); if (listExpressions.size() < tupleExpressions.size()) { addStaticTypeError("Incorrect number of values. Expected:" + tupleExpressions.size() + " Was:" + listExpressions.size(), list); return false; } for (int i = 0, tupleExpressionsSize = tupleExpressions.size(); i < tupleExpressionsSize; i++) { Expression tupleExpression = tupleExpressions.get(i); Expression listExpression = listExpressions.get(i); ClassNode elemType = getType(listExpression); ClassNode tupleType = getType(tupleExpression); if (!isAssignableTo(elemType, tupleType)) { addStaticTypeError("Cannot assign value of type " + elemType.toString(false) + " to variable of type " + tupleType.toString(false), rightExpression); return false; // avoids too many errors } else { storeType(tupleExpression, elemType); } } return true; }
private void checkTypeGenerics(ClassNode leftExpressionType, ClassNode wrappedRHS, Expression rightExpression) { // last, check generic type information to ensure that inferred types are compatible if (!leftExpressionType.isUsingGenerics()) return; // List<Foo> l = new List() is an example for incomplete generics type info // we assume arity related errors are already handled here. if (hasRHSIncompleteGenericTypeInfo(wrappedRHS)) return; GenericsType gt = GenericsUtils.buildWildcardType(leftExpressionType); if (UNKNOWN_PARAMETER_TYPE.equals(wrappedRHS) || gt.isCompatibleWith(wrappedRHS) || isNullConstant(rightExpression)) return; addStaticTypeError("Incompatible generic argument types. Cannot assign " + wrappedRHS.toString(false) + " to: " + leftExpressionType.toString(false), rightExpression); }
/** * This exists to avoid a recursive definition of toString. The default toString * in GenericsType calls ClassNode.toString(), which calls GenericsType.toString(), etc. * @param genericsType * @return the string representing the generic type */ private String genericTypeAsString(GenericsType genericsType) { StringBuilder ret = new StringBuilder(genericsType.getName()); if (genericsType.getUpperBounds() != null) { ret.append(" extends "); for (int i = 0; i < genericsType.getUpperBounds().length; i++) { ClassNode classNode = genericsType.getUpperBounds()[i]; if (classNode.equals(this)) { ret.append(classNode.getName()); } else { ret.append(classNode.toString(false)); } if (i + 1 < genericsType.getUpperBounds().length) ret.append(" & "); } } else if (genericsType.getLowerBound() !=null) { ClassNode classNode = genericsType.getLowerBound(); if (classNode.equals(this)) { ret.append(" super ").append(classNode.getName()); } else { ret.append(" super ").append(classNode); } } return ret.toString(); }
private void checkAndAddCannotCallPrivateMethodError(MethodNode target, Expression receiver, ClassNode classNode, ClassNode declaringClass) { if (declaringClass != classNode) { controller.getSourceUnit().addError(new SyntaxException("Cannot call private method " + (target.isStatic() ? "static " : "") + declaringClass.toString(false) + "#" + target.getName() + " from class " + classNode.toString(false), receiver.getLineNumber(), receiver.getColumnNumber(), receiver.getLastLineNumber(), receiver.getLastColumnNumber())); } }
/** * Instructs the type checker that a property access is dynamic. * Calling this method automatically sets the handled flag to true. * @param pexp the property or attribute expression * @param returnType the type of the property */ public void makeDynamic(PropertyExpression pexp, ClassNode returnType) { context.getEnclosingMethod().putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, Boolean.TRUE); pexp.putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, returnType); storeType(pexp, returnType); setHandled(true); if (debug) { LOG.info("Turning '"+pexp.getText()+"' into a dynamic property access of type "+returnType.toString(false)); } }
/** * Instructs the type checker that an unresolved variable is a dynamic variable. * @param returnType the type of the dynamic variable * Calling this method automatically sets the handled flag to true. * @param vexp the dynamic variable */ public void makeDynamic(VariableExpression vexp, ClassNode returnType) { context.getEnclosingMethod().putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, Boolean.TRUE); vexp.putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, returnType); storeType(vexp, returnType); setHandled(true); if (debug) { LOG.info("Turning '"+vexp.getText()+"' into a dynamic variable access of type "+returnType.toString(false)); } }
@Override public void visitCastExpression(final CastExpression expression) { super.visitCastExpression(expression); if (!expression.isCoerce()) { ClassNode targetType = expression.getType(); Expression source = expression.getExpression(); ClassNode expressionType = getType(source); if (!checkCast(targetType, source) && !isDelegateOrOwnerInClosure(source)) { addStaticTypeError("Inconvertible types: cannot cast " + expressionType.toString(false) + " to " + targetType.toString(false), expression); } } storeType(expression, expression.getType()); }
private void addPrecisionErrors(ClassNode leftRedirect, ClassNode lhsType, ClassNode inferredrhsType, Expression rightExpression) { if (isNumberType(leftRedirect) && isNumberType(inferredrhsType)) { if (checkPossibleLossOfPrecision(leftRedirect, inferredrhsType, rightExpression)) { addStaticTypeError("Possible loss of precision from " + inferredrhsType + " to " + leftRedirect, rightExpression); return; } } // if left type is array, we should check the right component types if (!lhsType.isArray()) return; ClassNode leftComponentType = lhsType.getComponentType(); ClassNode rightRedirect = rightExpression.getType().redirect(); if (rightRedirect.isArray()) { ClassNode rightComponentType = rightRedirect.getComponentType(); if (!checkCompatibleAssignmentTypes(leftComponentType, rightComponentType)) { addStaticTypeError("Cannot assign value of type " + rightComponentType.toString(false) + " into array of type " + lhsType.toString(false), rightExpression); } } else if (rightExpression instanceof ListExpression) { for (Expression element : ((ListExpression) rightExpression).getExpressions()) { ClassNode rightComponentType = this.getType(element); if (!checkCompatibleAssignmentTypes(leftComponentType, rightComponentType) && !(isNullConstant(element) && !isPrimitiveType(leftComponentType))) { addStaticTypeError("Cannot assign value of type " + rightComponentType.toString(false) + " into array of type " + lhsType.toString(false), rightExpression); } } } }
public ClassNode parameterizedType(ClassNode baseType, ClassNode... genericsTypeArguments) { ClassNode result = baseType.getPlainNodeReference(); if (result.isUsingGenerics()) { GenericsType[] gts = new GenericsType[genericsTypeArguments.length]; int expectedLength = result.getGenericsTypes().length; if (expectedLength!=genericsTypeArguments.length) { throw new GroovyBugError("Expected number of generic type arguments for "+baseType.toString(false)+" is "+expectedLength + " but you gave "+genericsTypeArguments.length); } for (int i = 0; i < gts.length; i++) { gts[i] = new GenericsType(genericsTypeArguments[i]); } result.setGenericsTypes(gts); } return result; }
/** * @param callArguments * @param receiver * @deprecated this method is unused, replaced with {@link DelegatesTo} inference. */ @Deprecated protected void checkClosureParameters(final Expression callArguments, final ClassNode receiver) { if (callArguments instanceof ArgumentListExpression) { ArgumentListExpression argList = (ArgumentListExpression) callArguments; ClosureExpression closure = (ClosureExpression) argList.getExpression(0); Parameter[] parameters = closure.getParameters(); if (parameters.length > 1) { addStaticTypeError("Unexpected number of parameters for a with call", argList); } else if (parameters.length == 1) { Parameter param = parameters[0]; if (!param.isDynamicTyped() && !isAssignableTo(receiver, param.getType().redirect())) { addStaticTypeError("Expected parameter type: " + receiver.toString(false) + " but was: " + param.getType().redirect().toString(false), param); } } closure.putNodeMetaData(StaticTypesMarker.DELEGATION_METADATA, new DelegationMetadata( receiver, Closure.DELEGATE_FIRST, typeCheckingContext.delegationMetadata )); } }
/** * Used to instruct the type checker that the call is a dynamic method call. * Calling this method automatically sets the handled flag to true. * @param call the method call which is a dynamic method call * @param returnType the expected return type of the dynamic call * @return a virtual method node with the same name as the expected call */ public MethodNode makeDynamic(MethodCall call, ClassNode returnType) { TypeCheckingContext.EnclosingClosure enclosingClosure = context.getEnclosingClosure(); MethodNode enclosingMethod = context.getEnclosingMethod(); ((ASTNode)call).putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, returnType); if (enclosingClosure!=null) { enclosingClosure.getClosureExpression().putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, Boolean.TRUE); } else { enclosingMethod.putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, Boolean.TRUE); } setHandled(true); if (debug) { LOG.info("Turning "+call.getText()+" into a dynamic method call returning "+returnType.toString(false)); } return new MethodNode(call.getMethodAsString(), 0, returnType, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE); }
@Override public void visitPropertyExpression(final PropertyExpression pexp) { typeCheckingContext.pushEnclosingPropertyExpression(pexp); try { if (visitPropertyExpressionSilent(pexp, pexp)) return; if (!extension.handleUnresolvedProperty(pexp)) { Expression objectExpression = pexp.getObjectExpression(); addStaticTypeError("No such property: " + pexp.getPropertyAsString() + " for class: " + findCurrentInstanceOfClass(objectExpression, getType(objectExpression)).toString(false), pexp); } } finally { typeCheckingContext.popEnclosingPropertyExpression(); } }
protected boolean typeCheckMethodsWithGenericsOrFail(ClassNode receiver, ClassNode[] arguments, MethodNode candidateMethod, Expression location) { if (!typeCheckMethodsWithGenerics(receiver, arguments, candidateMethod)) { Map<GenericsTypeName, GenericsType> classGTs = GenericsUtils.extractPlaceholders(receiver); ClassNode[] ptypes = new ClassNode[candidateMethod.getParameters().length]; final Parameter[] parameters = candidateMethod.getParameters(); for (int i = 0; i < parameters.length; i++) { final Parameter parameter = parameters[i]; ClassNode type = parameter.getType(); ptypes[i] = fullyResolveType(type, classGTs); } addStaticTypeError("Cannot call " + toMethodGenericTypesString(candidateMethod) + receiver.toString(false) + "#" + toMethodParametersString(candidateMethod.getName(), ptypes) + " with arguments " + formatArgumentList(arguments), location); return false; } return true; }