package com.redhat.ceylon.eclipse.code.correct; import static com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType; import static com.redhat.ceylon.model.typechecker.model.ModelUtil.isTypeUnknown; import static com.redhat.ceylon.model.typechecker.model.ModelUtil.unionType; import com.redhat.ceylon.compiler.typechecker.tree.Node; import com.redhat.ceylon.compiler.typechecker.tree.Tree; import com.redhat.ceylon.compiler.typechecker.tree.Visitor; import com.redhat.ceylon.model.typechecker.model.Type; import com.redhat.ceylon.model.typechecker.model.TypedDeclaration; import com.redhat.ceylon.model.typechecker.model.Unit; class FindArgumentsVisitor extends Visitor { Tree.MemberOrTypeExpression smte; Tree.NamedArgumentList namedArgs; Tree.PositionalArgumentList positionalArgs; Type currentType; Type expectedType; boolean found = false; boolean inEnumeration = false; FindArgumentsVisitor(Tree.MemberOrTypeExpression smte) { this.smte = smte; } @Override public void visit(Tree.MemberOrTypeExpression that) { super.visit(that); if (that==smte) { expectedType = currentType; found = true; } } @Override public void visit(Tree.InvocationExpression that) { super.visit(that); if (that.getPrimary()==smte) { namedArgs = that.getNamedArgumentList(); positionalArgs = that.getPositionalArgumentList(); } } @Override public void visit(Tree.NamedArgument that) { Type ct = currentType; currentType = that.getParameter()==null ? null : that.getParameter().getType(); super.visit(that); currentType = ct; } @Override public void visit(Tree.PositionalArgument that) { if (inEnumeration) { inEnumeration = false; super.visit(that); inEnumeration = true; } else { Type ct = currentType; currentType = that.getParameter()==null ? null : that.getParameter().getType(); super.visit(that); currentType = ct; } } @Override public void visit(Tree.AttributeDeclaration that) { currentType = that.getType().getTypeModel(); super.visit(that); currentType = null; } /*@Override public void visit(Tree.Variable that) { currentType = that.getType().getTypeModel(); super.visit(that); currentType = null; }*/ @Override public void visit(Tree.Resource that) { Unit unit = that.getUnit(); currentType = unionType(unit.getDestroyableDeclaration().getType(), unit.getObtainableDeclaration().getType(), unit); super.visit(that); currentType = null; } @Override public void visit(Tree.BooleanCondition that) { currentType = that.getUnit().getBooleanDeclaration().getType(); super.visit(that); currentType = null; } @Override public void visit(Tree.ExistsCondition that) { Tree.Statement st = that.getVariable(); if (st instanceof Tree.Variable) { Type varType = ((Tree.Variable) st).getType().getTypeModel(); currentType = that.getUnit().getOptionalType(varType); } super.visit(that); currentType = null; } @Override public void visit(Tree.NonemptyCondition that) { Tree.Statement st = that.getVariable(); if (st instanceof Tree.Variable) { Type varType = ((Tree.Variable) st).getType().getTypeModel(); currentType = that.getUnit().getEmptyType(varType); } super.visit(that); currentType = null; } @Override public void visit(Tree.Exists that) { Type oit = currentType; currentType = that.getUnit().getAnythingDeclaration().getType(); super.visit(that); currentType = oit; } @Override public void visit(Tree.Nonempty that) { Unit unit = that.getUnit(); Type oit = currentType; currentType = unit.getSequentialType(unit.getAnythingDeclaration().getType()); super.visit(that); currentType = oit; } @Override public void visit(Tree.SatisfiesCondition that) { Type objectType = that.getUnit().getObjectDeclaration().getType(); currentType = objectType; super.visit(that); currentType = null; } @Override public void visit(Tree.ValueIterator that) { Type varType = that.getVariable().getType().getTypeModel(); currentType = that.getUnit().getIterableType(varType); super.visit(that); currentType = null; } /*@Override public void visit(Tree.PatternIterator that) { Type keyType = that.getKeyVariable().getType().getTypeModel(); Type valueType = that.getValueVariable().getType().getTypeModel(); currentType = that.getUnit().getIterableType(that.getUnit() .getEntryType(keyType, valueType)); super.visit(that); currentType = null; }*/ @Override public void visit(Tree.BinaryOperatorExpression that) { if (currentType==null) { //fallback strategy for binary operators //TODO: not quite appropriate for a // couple of them! Tree.Term rightTerm = that.getRightTerm(); Tree.Term leftTerm = that.getLeftTerm(); if (rightTerm!=null && !isTypeUnknown(rightTerm.getTypeModel())) { currentType = rightTerm.getTypeModel(); } if (leftTerm!=null) leftTerm.visit(this); if (leftTerm!=null && !isTypeUnknown(leftTerm.getTypeModel())) { currentType = leftTerm.getTypeModel(); } if (rightTerm!=null) rightTerm.visit(this); currentType = null; } else { super.visit(that); } } @Override public void visit(Tree.EntryOp that) { Unit unit = that.getUnit(); if (currentType!=null && currentType.getDeclaration().equals(unit.getEntryDeclaration())) { Type oit = currentType; currentType = unit.getKeyType(oit); if (that.getLeftTerm()!=null) { that.getLeftTerm().visit(this); } currentType = unit.getValueType(oit); if (that.getRightTerm()!=null) { that.getRightTerm().visit(this); } currentType = oit; } else { Type oit = currentType; currentType = that.getUnit().getObjectDeclaration().getType(); super.visit(that); currentType = oit; } } @Override public void visit(Tree.RangeOp that) { Unit unit = that.getUnit(); if (currentType!=null && unit.isIterableType(currentType)) { Type oit = currentType; currentType = unit.getIteratedType(oit); super.visit(that); currentType = oit; } else { Type oit = currentType; currentType = that.getUnit().getObjectDeclaration().getType(); super.visit(that); currentType = oit; } } @Override public void visit(Tree.SegmentOp that) { Unit unit = that.getUnit(); if (currentType!=null && unit.isIterableType(currentType)) { Type oit = currentType; currentType = unit.getIteratedType(oit); super.visit(that); currentType = oit; } else { Type oit = currentType; currentType = that.getUnit().getObjectDeclaration().getType(); super.visit(that); currentType = oit; } } @Override public void visit(Tree.IndexExpression that) { Unit unit = that.getUnit(); Tree.ElementOrRange eor = that.getElementOrRange(); Tree.Primary primary = that.getPrimary(); Type oit = currentType; Type indexType = unit.getObjectDeclaration().getType(); if (eor instanceof Tree.Element) { Tree.Expression e = ((Tree.Element) eor).getExpression(); if (e!=null && !isTypeUnknown(e.getTypeModel())) { indexType = e.getTypeModel(); } } if (eor instanceof Tree.ElementRange) { Tree.Expression l = ((Tree.ElementRange) eor).getLowerBound(); Tree.Expression u = ((Tree.ElementRange) eor).getUpperBound(); if (l!=null && !isTypeUnknown(l.getTypeModel())) { indexType = l.getTypeModel(); } else if (u!=null && !isTypeUnknown(u.getTypeModel())) { indexType = u.getTypeModel(); } } currentType = appliedType(unit.getCorrespondenceDeclaration(), indexType, unit.getDefiniteType(currentType)); if (primary!=null) { primary.visit(this); } currentType = unit.getObjectDeclaration().getType(); if (primary!=null && !isTypeUnknown(primary.getTypeModel())) { //TODO: move this to Unit! Type supertype = primary.getTypeModel() .getSupertype(unit.getCorrespondenceDeclaration()); if (supertype!=null && !supertype.getTypeArgumentList().isEmpty()) { currentType = supertype.getTypeArgumentList().get(0); } } if (eor!=null) { eor.visit(this); } currentType = oit; } @Override public void visit(Tree.LogicalOp that) { Unit unit = that.getUnit(); Type oit = currentType; currentType = unit.getBooleanDeclaration().getType(); super.visit(that); currentType = oit; } @Override public void visit(Tree.BitwiseOp that) { Unit unit = that.getUnit(); Type oit = currentType; currentType = unit.getSetType(unit.getObjectDeclaration().getType()).getType(); super.visit(that); currentType = oit; } @Override public void visit(Tree.NotOp that) { Unit unit = that.getUnit(); Type oit = currentType; currentType = unit.getBooleanDeclaration().getType(); super.visit(that); currentType = oit; } @Override public void visit(Tree.InOp that) { Unit unit = that.getUnit(); Type oit = currentType; currentType = unit.getObjectDeclaration().getType(); if (that.getLeftTerm()!=null) { that.getLeftTerm().visit(this); } currentType = unit.getCategoryDeclaration().getType(); if (that.getRightTerm()!=null) { that.getRightTerm().visit(this); } currentType = oit; } @Override public void visit(Tree.SequenceEnumeration that) { Unit unit = that.getUnit(); if (currentType!=null && unit.isIterableType(currentType)) { Type oit = currentType; boolean oie = inEnumeration; inEnumeration = true; currentType = unit.getIteratedType(oit); super.visit(that); currentType = oit; inEnumeration = oie; } else { Type oit = currentType; currentType = that.getUnit().getAnythingDeclaration().getType(); super.visit(that); currentType = oit; } } @Override public void visit(Tree.Tuple that) { Unit unit = that.getUnit(); if (currentType!=null && unit.isIterableType(currentType)) { Type oit = currentType; boolean oie = inEnumeration; inEnumeration = true; currentType = unit.getIteratedType(oit); super.visit(that); currentType = oit; inEnumeration = oie; } else { Type oit = currentType; currentType = that.getUnit().getAnythingDeclaration().getType(); super.visit(that); currentType = oit; } } @Override public void visit(Tree.SpecifierStatement that) { currentType = that.getBaseMemberExpression().getTypeModel(); Tree.SpecifierExpression se = that.getSpecifierExpression(); if (se!=null) { if (isTypeUnknown(currentType) && se.getExpression()!=null) { currentType = se.getExpression().getTypeModel(); } } else { currentType = null; } super.visit(that); currentType = null; } @Override public void visit(Tree.AssignmentOp that) { Type ct = currentType; Tree.Term leftTerm = that.getLeftTerm(); Tree.Term rightTerm = that.getRightTerm(); if (leftTerm!=null && rightTerm!=null) { currentType = leftTerm.getTypeModel(); if (isTypeUnknown(currentType) ) { currentType = rightTerm.getTypeModel(); } } else { currentType = null; } super.visit(that); currentType = ct; } @Override public void visit(Tree.Return that) { if (that.getDeclaration() instanceof TypedDeclaration) { currentType = ((TypedDeclaration) that.getDeclaration()).getType(); } super.visit(that); currentType = null; } @Override public void visit(Tree.Throw that) { super.visit(that); //set expected type to Exception } @Override public void visitAny(Node that) { if (!found) super.visitAny(that); } @Override public void visit(Tree.FunctionArgument that) { Type ct = currentType; currentType = null; super.visit(that); currentType = ct; } }