diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index 84bfdc7a3e31..f736828f97b7 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -19,7 +19,7 @@ all this too. """ from datetime import datetime -OUR_OWN_DATETIME = datetime(2010, 6, 3, 17, 13, 12) # datetime.now() of edit time +OUR_OWN_DATETIME = datetime(2010, 7, 9, 16, 1, 5) # datetime.now() of edit time # we could use script's ctime, but the actual running copy may have it all wrong. # # Note: DON'T FORGET TO UPDATE! @@ -347,7 +347,7 @@ optionalPart << ( | ellipsis ) -# this is our ideal target, with balancing paren and a multiline rest of doc. +# this is our ideal target, with balancing paren and a multiline rest of doc. paramSeqAndRest = paramSeq + Suppress(')') + Suppress(Optional(Regex(".*(?s)"))) def transformSeq(results, toplevel=True): @@ -555,6 +555,146 @@ class ModuleRedeclarator(object): PREDEFINED_MOD_CLASS_SIGS = { ("datetime", "timedelta", "__new__") : "(cls, days=None, seconds=None, microseconds=None, milliseconds=None, minutes=None, hours=None, weeks=None)", } + + # known properties of modules + # {{"module": {"class", "property" : ("letters", "getter")}}, + # where letters is any set of r,w,d (read, write, del) and "getter" is a source of typed getter. + # if vlue is None, the property should be omitted. + # read-only properties that return an object are not listed. + G_OBJECT = "lambda self: object()" + G_TYPE = "lambda self: type(object)" + G_DICT = "lambda self: {}" + G_STR = "lambda self: ''" + G_TUPLE = "lambda self: tuple()" + G_FLOAT = "lambda self: 0.0" + G_INT = "lambda self: 0" + G_BOOL = "lambda self: True" + + KNOWN_PROPS = { + BUILTIN_MOD_NAME: { + ("object", '__class__'): ('r', G_TYPE), + ("BaseException", '__dict__'): ('r', G_DICT), + ("BaseException", 'message'): ('rwd', G_STR), + ("BaseException",'args'): ('r', G_TUPLE), + ('complex','real'): ('r', G_FLOAT), + ('complex','imag'): ('r', G_FLOAT), + ("EnvironmentError", 'errno'): ('rwd', G_INT), + ("EnvironmentError", 'message'): ('rwd', G_STR), + ("EnvironmentError", 'strerror'): ('rwd', G_INT), + ("EnvironmentError", 'filename'): ('rwd', G_STR), + ("file", 'softspace'): ('r', G_BOOL), + ("file", 'name'): ('r', G_STR), + ("file", 'encoding'): ('r', G_STR), + ("file", 'mode'): ('r', G_STR), + ("file", 'closed'): ('r', G_BOOL), + ("file", 'newlines'): ('r', G_STR), + ("SyntaxError", 'text'): ('rwd', G_STR), + ("SyntaxError", 'print_file_and_line'): ('rwd', G_BOOL), + ("SyntaxError", 'filename'): ('rwd', G_STR), + ("SyntaxError", 'lineno'): ('rwd', G_INT), + ("SyntaxError", 'offset'): ('rwd', G_INT), + ("SyntaxError", 'msg'): ('rwd', G_STR), + ("SyntaxError", 'message'): ('rwd', G_STR), + ("slice", 'start'): ('r', G_INT), + ("slice", 'step'): ('r', G_INT), + ("slice", 'stop'): ('r', G_INT), + ("super", '__thisclass__'): ('r', G_TYPE), + ("super", '__self__'): ('r', G_TYPE), + ("super", '__self_class__'): ('r', G_TYPE), + ("SystemExit", 'message'): ('rwd', G_STR), + ("SystemExit", 'code'): ('rwd', G_OBJECT), + ("type", '__basicsize__'): ('r', G_INT), + ("type", '__itemsize__'): ('r', G_INT), + ("type", '__base__'): ('r', G_TYPE), + ("type", '__flags__'): ('r', G_INT), + ("type", '__mro__'): ('r', G_TUPLE), + ("type", '__bases__'): ('r', G_TUPLE), + ("type", '__dictoffset__'): ('r', G_INT), + ("type", '__dict__'): ('r', G_DICT), + ("type", '__name__'): ('r', G_STR), + ("type", '__weakrefoffset__'): ('r', G_INT), + ("UnicodeDecodeError", '__basicsize__'): None, + ("UnicodeDecodeError", '__itemsize__'): None, + ("UnicodeDecodeError", '__base__'): None, + ("UnicodeDecodeError", '__flags__'): ('rwd', G_INT), + ("UnicodeDecodeError", '__mro__'): None, + ("UnicodeDecodeError", '__bases__'): None, + ("UnicodeDecodeError", '__dictoffset__'): None, + ("UnicodeDecodeError", '__dict__'): None, + ("UnicodeDecodeError", '__name__'): None, + ("UnicodeDecodeError", '__weakrefoffset__'): None, + ("UnicodeEncodeError", 'end'): ('rwd', G_INT), + ("UnicodeEncodeError", 'encoding'): ('rwd', G_STR), + ("UnicodeEncodeError", 'object'): ('rwd', G_OBJECT), + ("UnicodeEncodeError", 'start'): ('rwd', G_INT), + ("UnicodeEncodeError", 'reason'): ('rwd', G_STR), + ("UnicodeEncodeError", 'message'): ('rwd', G_STR), + ("UnicodeTranslateError", 'end'): ('rwd', G_INT), + ("UnicodeTranslateError", 'encoding'): ('rwd', G_STR), + ("UnicodeTranslateError", 'object'): ('rwd', G_OBJECT), + ("UnicodeTranslateError", 'start'): ('rwd', G_INT), + ("UnicodeTranslateError", 'reason'): ('rwd', G_STR), + ("UnicodeTranslateError", 'message'): ('rwd', G_STR), + }, + '_ast': { + ("AST", '__dict__'): ('rd', G_DICT), + }, + 'posix': { + ("statvfs_result", 'f_flag'): ('r', G_INT), + ("statvfs_result", 'f_bavail'): ('r', G_INT), + ("statvfs_result", 'f_favail'): ('r', G_INT), + ("statvfs_result", 'f_files'): ('r', G_INT), + ("statvfs_result", 'f_frsize'): ('r', G_INT), + ("statvfs_result", 'f_blocks'): ('r', G_INT), + ("statvfs_result", 'f_ffree'): ('r', G_INT), + ("statvfs_result", 'f_bfree'): ('r', G_INT), + ("statvfs_result", 'f_namemax'): ('r', G_INT), + ("statvfs_result", 'f_bsize'): ('r', G_INT), + + ("stat_result", 'st_ctime'): ('r', G_INT), + ("stat_result", 'st_rdev'): ('r', G_INT), + ("stat_result", 'st_mtime'): ('r', G_INT), + ("stat_result", 'st_blocks'): ('r', G_INT), + ("stat_result", 'st_gid'): ('r', G_INT), + ("stat_result", 'st_nlink'): ('r', G_INT), + ("stat_result", 'st_ino'): ('r', G_INT), + ("stat_result", 'st_blksize'): ('r', G_INT), + ("stat_result", 'st_dev'): ('r', G_INT), + ("stat_result", 'st_size'): ('r', G_INT), + ("stat_result", 'st_mode'): ('r', G_INT), + ("stat_result", 'st_uid'): ('r', G_INT), + ("stat_result", 'st_atime'): ('r', G_INT), + }, + "pwd": { + ("struct_pwent", 'pw_dir'): ('r', G_STR), + ("struct_pwent", 'pw_gid'): ('r', G_INT), + ("struct_pwent", 'pw_passwd'): ('r', G_STR), + ("struct_pwent", 'pw_gecos'): ('r', G_STR), + ("struct_pwent", 'pw_shell'): ('r', G_STR), + ("struct_pwent", 'pw_name'): ('r', G_STR), + ("struct_pwent", 'pw_uid'): ('r', G_INT), + + ("struct_passwd", 'pw_dir'): ('r', G_STR), + ("struct_passwd", 'pw_gid'): ('r', G_INT), + ("struct_passwd", 'pw_passwd'): ('r', G_STR), + ("struct_passwd", 'pw_gecos'): ('r', G_STR), + ("struct_passwd", 'pw_shell'): ('r', G_STR), + ("struct_passwd", 'pw_name'): ('r', G_STR), + ("struct_passwd", 'pw_uid'): ('r', G_INT), + }, + "thread": { + ("_local", '__dict__'): None + }, + "xxsubtype": { + ("spamdict", 'state'): ('r', G_INT), + ("spamlist", 'state'): ('r', G_INT), + }, + "zipimport": { + ("zipimporter", 'prefix'): ('r', G_STR), + ("zipimporter", 'archive'): ('r', G_STR), + ("zipimporter", '_files'): ('r', G_DICT), + }, + } # Some builtin classes effectively change __init__ signature without overriding it. # This callable serves as a placeholder to be replaced via REDEFINED_BUILTIN_SIGS @@ -948,10 +1088,10 @@ class ModuleRedeclarator(object): self.out("class " + p_name + base_def + ":", indent) self.outDocAttr(p_class, indent+1) # inner parts + methods = {} + properties = {} + others = {} if hasattr(p_class, "__dict__"): - methods = {} - properties = {} - others = {} we_are_the_base_class = p_modname == BUILTIN_MOD_NAME and p_name in ("object", FAKE_CLASSOBJ_NAME) for item_name in p_class.__dict__: if item_name in ("__doc__", "__module__"): @@ -978,9 +1118,24 @@ class ModuleRedeclarator(object): item = methods[item_name] self.redoFunction(item, item_name, indent+1, p_class, p_modname) # + known_props = self.KNOWN_PROPS.get(p_modname, {}) + a_setter = "lambda self, v: None" + a_deleter = "lambda self: None" for item_name in sortedNoCase(properties.keys()): - item = properties[item_name] - self.out(item_name + " = property(None, None, None)", indent+1) # TODO: handle docstring + prop_key = (p_name, item_name) + if known_props.has_key(prop_key): + prop_descr = known_props.get(prop_key, None) + if prop_descr is None: + continue # explicitly omitted + acc_line, getter = prop_descr + accessors = [] + accessors.append("r" in acc_line and getter or "None") + accessors.append("w" in acc_line and a_setter or "None") + accessors.append("d" in acc_line and a_deleter or "None") + self.out(item_name + " = property(" + ", ".join(accessors) + ")", indent+1) + else: + self.out(item_name + " = property(lambda self: object(), None, None) # default", indent+1) + # TODO: handle docstring if properties: self.out("", 0) # empty line after the block # @@ -1015,7 +1170,7 @@ class ModuleRedeclarator(object): if hasattr(item, "__name__"): self.out("import " + item.__name__ + " as " + item_name + " # refers to " + str(item)) else: - self.out(item_name + " = None # XXX name unknown, refers to " + str(item)) + self.out(item_name + " = None # ??? name unknown, refers to " + str(item)) self.out("", 0) # empty line after imports # group what else we have into buckets vars_simple = {} diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index 2858db18833a..72c7639ec5cd 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -49,4 +49,9 @@ public class PyJavaClassType implements PyType { return myClass.getName(); else return null; } + + @Override + public boolean isBuiltin() { + return false; // TODO: JSDK's types could be considered built-in. + } } diff --git a/python/src/com/jetbrains/python/PyTokenTypes.java b/python/src/com/jetbrains/python/PyTokenTypes.java index 063b0d23a43b..2cd20247c0c7 100644 --- a/python/src/com/jetbrains/python/PyTokenTypes.java +++ b/python/src/com/jetbrains/python/PyTokenTypes.java @@ -20,7 +20,7 @@ public class PyTokenTypes { public static final PyElementType END_OF_LINE_COMMENT = new PyElementType("END_OF_LINE_COMMENT"); - public static final PyElementType AND_KEYWORD = new PyElementType("AND_KEYWORD"); + public static final PyElementType AND_KEYWORD = new PyElementType("AND_KEYWORD", "__and__"); public static final PyElementType AS_KEYWORD = new PyElementType("AS_KEYWORD"); public static final PyElementType ASSERT_KEYWORD = new PyElementType("ASSERT_KEYWORD"); public static final PyElementType BREAK_KEYWORD = new PyElementType("BREAK_KEYWORD"); @@ -42,7 +42,7 @@ public class PyTokenTypes { public static final PyElementType IS_KEYWORD = new PyElementType("IS_KEYWORD"); public static final PyElementType LAMBDA_KEYWORD = new PyElementType("LAMBDA_KEYWORD"); public static final PyElementType NOT_KEYWORD = new PyElementType("NOT_KEYWORD"); - public static final PyElementType OR_KEYWORD = new PyElementType("OR_KEYWORD"); + public static final PyElementType OR_KEYWORD = new PyElementType("OR_KEYWORD", "__or__"); public static final PyElementType PASS_KEYWORD = new PyElementType("PASS_KEYWORD"); public static final PyElementType PRINT_KEYWORD = new PyElementType("PRINT_KEYWORD"); public static final PyElementType RAISE_KEYWORD = new PyElementType("RAISE_KEYWORD"); @@ -75,26 +75,26 @@ public class PyTokenTypes { public static final PyElementType STRING_LITERAL = new PyElementType("STRING_LITERAL"); // Operators - public static final PyElementType PLUS = new PyElementType("PLUS");// + - public static final PyElementType MINUS = new PyElementType("MINUS");// - - public static final PyElementType MULT = new PyElementType("MULT");// * - public static final PyElementType EXP = new PyElementType("EXP");// ** - public static final PyElementType DIV = new PyElementType("DIV"); // / - public static final PyElementType FLOORDIV = new PyElementType("FLOORDIV"); // // - public static final PyElementType PERC = new PyElementType("PERC");// % - public static final PyElementType LTLT = new PyElementType("LTLT");// << - public static final PyElementType GTGT = new PyElementType("GTGT");// >> - public static final PyElementType AND = new PyElementType("AND");// & - public static final PyElementType OR = new PyElementType("OR");// | - public static final PyElementType XOR = new PyElementType("XOR");// ^ - public static final PyElementType TILDE = new PyElementType("TILDE");// ~ - public static final PyElementType LT = new PyElementType("LT");// < - public static final PyElementType GT = new PyElementType("GT");// > - public static final PyElementType LE = new PyElementType("LE");// <= - public static final PyElementType GE = new PyElementType("GE");// >= - public static final PyElementType EQEQ = new PyElementType("EQEQ");// == - public static final PyElementType NE = new PyElementType("NE");// != - public static final PyElementType NE_OLD = new PyElementType("NE_OLD");// <> + public static final PyElementType PLUS = new PyElementType("PLUS", "__add__");// + + public static final PyElementType MINUS = new PyElementType("MINUS", "__sub__");// - + public static final PyElementType MULT = new PyElementType("MULT", "__mul__");// * + public static final PyElementType EXP = new PyElementType("EXP", "__pow__");// ** + public static final PyElementType DIV = new PyElementType("DIV", "__div__"); // / + public static final PyElementType FLOORDIV = new PyElementType("FLOORDIV", "__floordiv__"); // // + public static final PyElementType PERC = new PyElementType("PERC", "__mod__");// % + public static final PyElementType LTLT = new PyElementType("LTLT", "__lshift__");// << + public static final PyElementType GTGT = new PyElementType("GTGT", "__rshift__");// >> + public static final PyElementType AND = new PyElementType("AND", "__and__");// & + public static final PyElementType OR = new PyElementType("OR", "__or__");// | + public static final PyElementType XOR = new PyElementType("XOR", "__xor__");// ^ + public static final PyElementType TILDE = new PyElementType("TILDE", "__invert__");// ~ + public static final PyElementType LT = new PyElementType("LT", "__lt__");// < + public static final PyElementType GT = new PyElementType("GT", "__gt__");// > + public static final PyElementType LE = new PyElementType("LE", "__le__");// <= + public static final PyElementType GE = new PyElementType("GE", "__ge__");// >= + public static final PyElementType EQEQ = new PyElementType("EQEQ", "__eq__");// == + public static final PyElementType NE = new PyElementType("NE", "__ne__");// != + public static final PyElementType NE_OLD = new PyElementType("NE_OLD", "__ne__");// <> // Delimiters public static final PyElementType LPAR = new PyElementType("LPAR");// ( diff --git a/python/src/com/jetbrains/python/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/PythonDocumentationProvider.java index b6fd1ecccb99..cca50954afc6 100644 --- a/python/src/com/jetbrains/python/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/PythonDocumentationProvider.java @@ -49,11 +49,11 @@ public class PythonDocumentationProvider extends QuickDocumentationProvider { cat.append("class ").append(cls_name).append("\n "); // It would be nice to have class import info here, but we don't know the ctrl+hovered reference and context } - return describeFunction(func, LSame2, ", ", LSame2, LSame1).toString(); + return describeDecorators(func, LSame2, ", ", LSame1).add(describeFunction(func, LSame2, LSame1)).toString(); } else if (element instanceof PyClass) { PyClass cls = (PyClass)element; - return describeClass(cls, LSame2).toString(); + return describeDecorators(cls, LSame2, ", ", LSame1).add(describeClass(cls, LSame2)).toString(); } return null; } @@ -75,18 +75,10 @@ public class PythonDocumentationProvider extends QuickDocumentationProvider { */ private static ChainIterable describeFunction( PyFunction fun, - FP.Lambda1, Iterable> deco_name_wrapper, - String deco_separator, FP.Lambda1, Iterable> func_name_wrapper, FP.Lambda1 escaper ) { ChainIterable cat = new ChainIterable(null); - PyDecoratorList deco_list = fun.getDecoratorList(); - if (deco_list != null) { - for (PyDecorator deco : deco_list.getDecorators()) { - cat.add(describeDeco(deco, deco_name_wrapper, escaper)).add(deco_separator); // can't easily pass describeDeco to map() %) - } - } cat.add("def ").addWith(func_name_wrapper, $(fun.getName())); cat.add(escaper.apply(PyUtil.getReadableRepr(fun.getParameterList(), false))); final PyType returnType = fun.getReturnType(); @@ -96,6 +88,20 @@ public class PythonDocumentationProvider extends QuickDocumentationProvider { return cat; } + private static ChainIterable describeDecorators( + PyDecoratable what, FP.Lambda1, Iterable> deco_name_wrapper, + String deco_separator, FP.Lambda1 escaper + ) { + ChainIterable cat = new ChainIterable(); + PyDecoratorList deco_list = what.getDecoratorList(); + if (deco_list != null) { + for (PyDecorator deco : deco_list.getDecorators()) { + cat.add(describeDeco(deco, deco_name_wrapper, escaper)).add(deco_separator); // can't easily pass describeDeco to map() %) + } + } + return cat; + } + /** * Creates a HTML description of function definition. * @param cls the class @@ -112,7 +118,6 @@ public class PythonDocumentationProvider extends QuickDocumentationProvider { if (ancestors.length > 0) { cat.add("(").add(interleave(FP.map(LReadableRepr, ancestors), ", ")).add(")"); } - // TODO: for py3k, show decorators return cat; } @@ -260,6 +265,7 @@ public class PythonDocumentationProvider extends QuickDocumentationProvider { // doc of what? if (followed instanceof PyClass) { cls = (PyClass)followed; + doc_cat.add(describeDecorators(cls, TagItalic, BR, LCombUp)); doc_cat.addWith(TagSmall, describeClass(cls, TagBold)); } else if (followed instanceof PyFunction) { @@ -269,7 +275,7 @@ public class PythonDocumentationProvider extends QuickDocumentationProvider { if (cls != null) doc_cat.addWith(TagSmall, $("class ", cls.getName(), BR)); } else cls = null; - doc_cat.add(describeFunction(fun, TagItalic, BR, TagBold, LCombUp)); + doc_cat.add(describeDecorators(fun, TagItalic, BR, LCombUp)).add(describeFunction(fun, TagBold, LCombUp)); if (docString == null) { addInheritedDocString(fun, cls, doc_cat, epilog_cat); } diff --git a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java index 1160fc14af89..557bf86ec02b 100644 --- a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java @@ -7,6 +7,9 @@ import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.console.PydevConsoleRunner; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.types.PyClassType; +import com.jetbrains.python.psi.types.PyType; +import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -56,6 +59,27 @@ public class PyStatementEffectInspection extends PyInspection { return; } } + else if (expression instanceof PyBinaryExpression) { + PyBinaryExpression binary = (PyBinaryExpression)expression; + String method = binary.getOperator().getSpecialMethodName(); + if (method != null) { + // maybe the op is overridden and may produce side effects, like cout << "hello" + PyType type = binary.getLeftExpression().getType(TypeEvalContext.fast()); + if (type != null && ! type.isBuiltin() && type.resolveMember(method, AccessDirection.READ) != null) { + return; + } + final PyExpression rhs = binary.getRightExpression(); + if (rhs != null) { + type = rhs.getType(TypeEvalContext.fast()); + if (type != null) { + String rmethod = "__r" + method.substring(2); // __add__ -> __radd__ + if (! type.isBuiltin() && type.resolveMember(rmethod, AccessDirection.READ) != null) { + return; + } + } + } + } + } final PyTryPart tryPart = PsiTreeUtil.getParentOfType(node, PyTryPart.class); if (tryPart != null) { diff --git a/python/src/com/jetbrains/python/psi/PyClass.java b/python/src/com/jetbrains/python/psi/PyClass.java index a600dd673d7a..0eb61885fe09 100644 --- a/python/src/com/jetbrains/python/psi/PyClass.java +++ b/python/src/com/jetbrains/python/psi/PyClass.java @@ -16,7 +16,9 @@ import java.util.List; /** * Represents a class declaration in source. */ -public interface PyClass extends PsiNamedElement, PyStatement, NameDefiner, PyDocStringOwner, StubBasedPsiElement, ScopeOwner { +public interface PyClass extends + PsiNamedElement, PyStatement, NameDefiner, PyDocStringOwner, StubBasedPsiElement, ScopeOwner, PyDecoratable +{ @Nullable ASTNode getNameNode(); @@ -101,8 +103,6 @@ public interface PyClass extends PsiNamedElement, PyStatement, NameDefiner, PyDo */ boolean isSubclass(PyClass parent); - @Nullable - PyDecoratorList getDecoratorList(); String getQualifiedName(); diff --git a/python/src/com/jetbrains/python/psi/PyDecoratable.java b/python/src/com/jetbrains/python/psi/PyDecoratable.java new file mode 100644 index 000000000000..a30cd758d2c6 --- /dev/null +++ b/python/src/com/jetbrains/python/psi/PyDecoratable.java @@ -0,0 +1,13 @@ +package com.jetbrains.python.psi; + +import org.jetbrains.annotations.Nullable; + +/** + * TODO: Add description + * User: dcheryasov + * Date: Jul 8, 2010 3:48:14 AM + */ +public interface PyDecoratable { + @Nullable + PyDecoratorList getDecoratorList(); +} diff --git a/python/src/com/jetbrains/python/psi/PyElementType.java b/python/src/com/jetbrains/python/psi/PyElementType.java index 0caf5ea33b73..2b978d61d4e4 100644 --- a/python/src/com/jetbrains/python/psi/PyElementType.java +++ b/python/src/com/jetbrains/python/psi/PyElementType.java @@ -18,15 +18,23 @@ public class PyElementType extends IElementType { private static final Class[] PARAMETER_TYPES = new Class[]{ASTNode.class}; private Constructor myConstructor; + private String mySpecialMethodName; + public PyElementType(@NotNull @NonNls String debugName) { super(debugName, PythonFileType.INSTANCE.getLanguage()); } + public PyElementType(@NonNls String debugName, Class psiElementClass) { this(debugName); _psiElementClass = psiElementClass; } + public PyElementType(@NotNull @NonNls String debugName, @NotNull @NonNls String specialMethodName) { + this(debugName); + mySpecialMethodName = specialMethodName; + } + @Nullable public PsiElement createElement(ASTNode node) { if (_psiElementClass == null) { @@ -45,6 +53,13 @@ public class PyElementType extends IElementType { } } + /** + * @return name of special method for operation marked by this token; e.g. "__add__" for "+". + */ + public String getSpecialMethodName() { + return mySpecialMethodName; + } + @Override public String toString() { return "Py:" + super.toString(); diff --git a/python/src/com/jetbrains/python/psi/PyFunction.java b/python/src/com/jetbrains/python/psi/PyFunction.java index 491bd7d22722..7d75ffe59e50 100644 --- a/python/src/com/jetbrains/python/psi/PyFunction.java +++ b/python/src/com/jetbrains/python/psi/PyFunction.java @@ -17,8 +17,7 @@ import org.jetbrains.annotations.Nullable; public interface PyFunction extends PsiNamedElement, StubBasedPsiElement, - PsiNameIdentifierOwner, PyStatement, Callable, NameDefiner, PyDocStringOwner, ScopeOwner -{ + PsiNameIdentifierOwner, PyStatement, Callable, NameDefiner, PyDocStringOwner, ScopeOwner, PyDecoratable { PyFunction[] EMPTY_ARRAY = new PyFunction[0]; /** @@ -36,9 +35,6 @@ extends @Nullable PyClass getContainingClass(); - @Nullable - PyDecoratorList getDecoratorList(); - /** * Returns true if the function is a top-level class (its parent is its containing file). * diff --git a/python/src/com/jetbrains/python/psi/types/PyClassType.java b/python/src/com/jetbrains/python/psi/types/PyClassType.java index 5aaa529af0d3..c5523961d831 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassType.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassType.java @@ -231,6 +231,11 @@ public class PyClassType implements PyType { } } + @Override + public boolean isBuiltin() { + return PyBuiltinCache.getInstance(myClass).hasInBuiltins(myClass); + } + @NotNull public Set getPossibleInstanceMembers() { Set ret = new HashSet(); diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index ca0860d7738d..98876bd9fd55 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -55,4 +55,9 @@ public class PyImportedModuleType implements PyType { public String getName() { return "PyImportedModuleType:" + myImportedModule.toString(); } + + @Override + public boolean isBuiltin() { + return false; // no module can be imported from builtins + } } diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index 087984ecca31..160c1b4ea389 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -119,6 +119,11 @@ public class PyModuleType implements PyType { // Maybe make it a PyClassType ref else return null; } + @Override + public boolean isBuiltin() { + return true; + } + @NotNull public static Set getPossibleInstanceMembers() { return ourPossibleFields; diff --git a/python/src/com/jetbrains/python/psi/types/PyNoneType.java b/python/src/com/jetbrains/python/psi/types/PyNoneType.java index 45f833a04e2f..7f1f3c15d642 100644 --- a/python/src/com/jetbrains/python/psi/types/PyNoneType.java +++ b/python/src/com/jetbrains/python/psi/types/PyNoneType.java @@ -31,4 +31,9 @@ public class PyNoneType implements PyType { // TODO must extend ClassType. It's public String getName() { return "None"; } + + @Override + public boolean isBuiltin() { + return true; + } } diff --git a/python/src/com/jetbrains/python/psi/types/PyReturnTypeReference.java b/python/src/com/jetbrains/python/psi/types/PyReturnTypeReference.java index 31293a0ae98e..97f24f0a0f8c 100644 --- a/python/src/com/jetbrains/python/psi/types/PyReturnTypeReference.java +++ b/python/src/com/jetbrains/python/psi/types/PyReturnTypeReference.java @@ -3,6 +3,7 @@ package com.jetbrains.python.psi.types; import com.intellij.psi.PsiElement; import com.jetbrains.python.psi.Callable; import com.jetbrains.python.psi.PyFunction; +import com.jetbrains.python.psi.impl.PyBuiltinCache; import org.jetbrains.annotations.Nullable; /** @@ -23,4 +24,10 @@ public class PyReturnTypeReference extends PyTypeReferenceImpl { public String getName() { return "return type of " + myCallable.getPresentation().getPresentableText(); } + + @Override + public boolean isBuiltin() { + PyType type = myCallable.getReturnType(); + return type != null && type.isBuiltin(); + } } diff --git a/python/src/com/jetbrains/python/psi/types/PyTupleType.java b/python/src/com/jetbrains/python/psi/types/PyTupleType.java index 8885eec86e66..1b08310f865a 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTupleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyTupleType.java @@ -33,6 +33,11 @@ public class PyTupleType extends PyClassType implements PySubscriptableType { }, ",") + ")"; } + @Override + public boolean isBuiltin() { + return true; + } + public PyType getElementType(PyExpression index, TypeEvalContext context) { final Object value = PyConstantExpressionEvaluator.evaluate(index); if (value instanceof Integer) { diff --git a/python/src/com/jetbrains/python/psi/types/PyType.java b/python/src/com/jetbrains/python/psi/types/PyType.java index 17de658e59ba..f895f850e57b 100644 --- a/python/src/com/jetbrains/python/psi/types/PyType.java +++ b/python/src/com/jetbrains/python/psi/types/PyType.java @@ -48,4 +48,9 @@ public interface PyType { @Nullable String getName(); + /** + * @return true if the type is a known built-in type. + */ + boolean isBuiltin(); + } diff --git a/python/src/com/jetbrains/python/psi/types/PyUnionType.java b/python/src/com/jetbrains/python/psi/types/PyUnionType.java index 7d602e88c7cb..3552305236be 100644 --- a/python/src/com/jetbrains/python/psi/types/PyUnionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyUnionType.java @@ -55,6 +55,17 @@ public class PyUnionType implements PyType { }, ", ") + ")"; } + /** + * @return true if all types in the union are built-in. + */ + @Override + public boolean isBuiltin() { + for (PyType one : myMembers) { + if (! one.isBuiltin()) return false; + } + return true; + } + @Nullable public static PyType union(PyType type1, PyType type2) { if (type1 instanceof PyTupleType && type2 instanceof PyTupleType) {