package org.yinwang.pysonar.ast; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.yinwang.pysonar.Binding; import org.yinwang.pysonar.Indexer; import org.yinwang.pysonar.Scope; import org.yinwang.pysonar.Util; import org.yinwang.pysonar.types.Type; import org.yinwang.pysonar.types.UnionType; import java.util.Set; import static org.yinwang.pysonar.Binding.Kind.ATTRIBUTE; public class Attribute extends Node { @NotNull public Node target; @NotNull public Name attr; public Attribute(@NotNull Node target, @NotNull Name attr, int start, int end) { super(start, end); this.target = target; this.attr = attr; addChildren(target, attr); } @Nullable public String getAttributeName() { return attr.getId(); } public void setAttr(@NotNull Name attr) { this.attr = attr; } @NotNull public Name getAttr() { return attr; } public void setTarget(@NotNull Node target) { this.target = target; } @Nullable public Node getTarget() { return target; } public void setAttr(Scope s, @NotNull Type v, int tag) { Type targetType = resolveExpr(target, s, tag); if (targetType.isUnionType()) { Set<Type> types = targetType.asUnionType().getTypes(); for (Type tp : types) { setAttrType(tp, v, tag); } } else { setAttrType(targetType, v, tag); } } private void setAttrType(@NotNull Type targetType, @NotNull Type v, int tag) { if (targetType.isUnknownType()) { Indexer.idx.putProblem(this, "Can't set attribute for UnknownType"); return; } targetType.getTable().putAttr(attr.getId(), attr, v, ATTRIBUTE, tag); } @NotNull @Override public Type resolve(Scope s, int tag) { Type targetType = resolveExpr(target, s, tag); if (targetType.isUnionType()) { Set<Type> types = targetType.asUnionType().getTypes(); Type retType = Indexer.idx.builtins.unknown; for (Type tt : types) { retType = UnionType.union(retType, getAttrType(tt)); } return retType; } else { return getAttrType(targetType); } } private Type getAttrType(@NotNull Type targetType) { Binding b = targetType.getTable().lookupAttr(attr.getId()); if (b == null) { Indexer.idx.putProblem(attr, "attribute not found in type: " + targetType); Type t = Indexer.idx.builtins.unknown; t.getTable().setPath(targetType.getTable().extendPath(attr.getId())); return t; } else { Indexer.idx.putRef(attr, b); if (b.getType() == null) { Util.msg("b.getType() is null!"); } if (getParent() == null) { Util.msg("parent is null!"); } if (getParent() != null && getParent().isCall() && b.getType().isFuncType() && targetType.isInstanceType()) { // method call b.getType().asFuncType().setSelfType(targetType); } return b.getType(); } } @NotNull @Override public String toString() { return "<Attribute:" + start + ":" + target + "." + getAttributeName() + ">"; } @Override public void visit(@NotNull NodeVisitor v) { if (v.visit(this)) { visitNode(target, v); visitNode(attr, v); } } }