package org.yinwang.pysonar; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.yinwang.pysonar.ast.*; /** * Encapsulates information about a binding definition site. */ public class Def { // Being frugal with fields here is good for memory usage. private int start = -1; private int end = -1; private int bodyStart = -1; private int bodyEnd = -1; public String docstring; public int docstringStart; public int docstringEnd; @NotNull private Binding binding; @Nullable private String fileOrUrl; @Nullable private String name; private Node node; public Def(Node node, @NotNull Binding binding) { this.node = node; this.binding = binding; if (node instanceof Url) { String url = ((Url) node).getURL(); if (url.startsWith("file://")) { fileOrUrl = url.substring("file://".length()); } else { fileOrUrl = url; } } else { fileOrUrl = node.getFile(); if (node instanceof Name) { name = node.asName().getId(); } } initLocationInfo(node); } private void initLocationInfo(Node node) { start = node.start; end = node.end; Node parent = node.getParent(); if ((parent instanceof FunctionDef && ((FunctionDef)parent).name == node) || (parent instanceof ClassDef && ((ClassDef)parent).name == node)) { bodyStart = parent.start; bodyEnd = parent.end; Str docstring = parent.docstring(); if (docstring != null ) { this.docstring = docstring.getStr(); this.docstringStart = docstring.start; this.docstringEnd = docstring.end; } } else if (node instanceof Module) { name = ((Module) node).name; start = 0; end = 0; bodyStart = node.start; bodyEnd = node.end; Str docstring = node.docstring(); if (docstring != null ) { this.docstring = docstring.getStr(); this.docstringStart = docstring.start; this.docstringEnd = docstring.end; } } else { bodyStart = node.start; bodyEnd = node.end; } // Util.msg("start: " + start + ", end: " + end + ", bodystart: " + bodyStart + ", bodyend: " + bodyEnd); } /** * Returns the name of the node. Only applies if the definition coincides * with a {@link org.yinwang.pysonar.ast.Name} node. * * @return the name, or null */ @Nullable public String getName() { return name; } /** * Returns the file if this node is from a source file, else {@code null}. */ @Nullable public String getFile() { return isURL() ? null : fileOrUrl; } /** * Returns the URL if this node is from a URL, else {@code null}. */ @Nullable public String getURL() { return isURL() ? fileOrUrl : null; } /** * Returns the file if from a source file, else the URL. */ @Nullable public String getFileOrUrl() { return fileOrUrl; } /** * Returns {@code true} if this node is from a URL. */ public boolean isURL() { return fileOrUrl != null && fileOrUrl.startsWith("http://"); } public boolean isModule() { return binding.getKind() == Binding.Kind.MODULE; } public int getStart() { return start; } public int getEnd() { return end; } public int getLength() { return end - start; } public int getBodyStart() { return bodyStart; } public int getBodyEnd() { return bodyEnd; } public boolean isName() { return name != null; } void setBinding(Binding b) { binding = b; } @NotNull public Binding getBinding() { return binding; } public Node getNode() { return node; } public void setNode(Node node) { this.node = node; } @NotNull @Override public String toString() { return "<Def:" + (name == null ? "" : name) + ":" + Util.baseFileName(fileOrUrl) + ":" + start + ">"; } @Override public boolean equals(Object obj) { if (!(obj instanceof Def)) { return false; } else { Def def = (Def) obj; return (start == def.start && end == def.end && ((fileOrUrl == null && def.fileOrUrl == null) || (fileOrUrl != null && def.fileOrUrl != null && fileOrUrl.equals(def.fileOrUrl)))); } } @Override public int hashCode() { return ("" + fileOrUrl + start).hashCode(); } }