/** * Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ /* * Created on Sep 21, 2006 * @author Fabio */ package com.python.pydev.analysis; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eclipse.core.resources.IMarker; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.text.Document; import org.python.pydev.core.ICompletionState; import org.python.pydev.core.IPythonNature; import org.python.pydev.core.MisconfigurationException; import org.python.pydev.core.TestDependent; import org.python.pydev.editor.autoedit.TestIndentPrefs; import org.python.pydev.editor.codecompletion.revisited.modules.AbstractModule; import org.python.pydev.editor.codecompletion.revisited.modules.SourceModule; import org.python.pydev.shared_core.callbacks.CallbackWithListeners; import org.python.pydev.shared_core.callbacks.ICallbackListener; import org.python.pydev.shared_core.io.FileUtils; import org.python.pydev.shared_core.string.StringUtils; import com.python.pydev.analysis.messages.IMessage; public class OccurrencesAnalyzer2Test extends AnalysisTestsBase { public static void main(String[] args) { try { OccurrencesAnalyzer2Test analyzer2 = new OccurrencesAnalyzer2Test(); analyzer2.setUp(); analyzer2.testParameterAnalysis27a(); analyzer2.tearDown(); System.out.println("finished"); junit.textui.TestRunner.run(OccurrencesAnalyzer2Test.class); System.out.println("finished all"); } catch (Throwable e) { e.printStackTrace(); } System.exit(0); } @Override public void setUp() throws Exception { super.setUp(); prefs.severityForArgumentsMismatch = IMarker.SEVERITY_ERROR; } public void testErrorNotShownOnDynamicClass() { doc = new Document("from extendable.noerr import importer\n" + "print importer.getWithAttr.whatever\n"); checkNoError(); } public void testErrorNotShownOnDynamicClass2() { doc = new Document("from extendable.noerr import importer\n" + "print importer.getWithAttr.whatever.other\n"); checkNoError(); } public void testErrorNotShownOnDynamicClass3() { doc = new Document("from extendable.noerr import importer\n" + "print importer.childGetWithAttr.whatever\n" + "print importer.childGetWithAttr.whatever.other\n"); checkNoError(); } public void testErrorNotShownOnClassFromMethod() { doc = new Document("from extendable.noerr import importer\n" + "print importer.logger.debug('10')\n"); checkNoError(); } public void testErrorNotShownOnNoneClass() { doc = new Document("from extendable.noerr import importer\n" + "print importer.initialNone.foo\n"); checkNoError(); } public void testErrorNotShownOnDynamicClass4() { doc = new Document("from extendable.noerr import importer\n" + "print importer.globals_struct.bar\n"); checkNoError(); } public void testErrorNotShownOnDynamicClass5() { doc = new Document("from extendable.noerr import importer\n" + "print importer.Struct.bar\n"); checkNoError(); } public void testErrorNotShownOnDynamicClass6() { doc = new Document("from extendable.noerr.importer import WithGetAttr2\n" + "print WithGetAttr2.anything\n"); checkNoError(); } public void testErrorNotShownOnDynamicClass7() { doc = new Document("from extendable.noerr.importer import Struct\n" + "print Struct.anything\n"); checkNoError(); } public void testErrorNotShownOnDynamicClass8() { doc = new Document("from extendable.noerr.importer import StructSub\n" + "print StructSub.anything\n"); checkNoError(); } public void testErrorShownOnInitialSetClass() { doc = new Document("from extendable.noerr import importer\n" + "print importer.initialSet.m1\n" + "print importer.initialSet.m2\n"//has error ); IMessage[] messages = checkError(1); assertEquals("Undefined variable from import: m2", messages[0].getMessage()); } public void testNoErrorPathInPackage() { doc = new Document("import extendable\n" + "print extendable.__path__\n"); checkNoError(); } public void testErrorPathNotInModule() { doc = new Document("from extendable import static\n" + "print static.__path__\n"); IMessage[] messages = checkError(1); assertEquals("Undefined variable from import: __path__", messages[0].getMessage()); } public void testErrorPathNotInModule2() { doc = new Document("from extendable import * #@UnusedWildImport\n" + "__path__\n"); //__path__ does not come on "import *" IMessage[] messages = checkError(1); assertEquals("Undefined variable: __path__", messages[0].getMessage()); } public void testNoEffectInException() { doc = new Document("def raise_exception():\n" + " x = None\n" + " raise Exception, '%(number)s' % {\n" + " 'number': x is None,\n" + " }\n"); checkNoError(); } public void testNoEffectInGenExp() { doc = new Document("for val in (3 in (1, 2), 'something else'):\n" + " print 'val was', val\n"); checkNoError(); } public void testPathFound() throws IOException, MisconfigurationException { analyzer = new OccurrencesAnalyzer(); File file = new File(TestDependent.TEST_PYSRC_LOC + "extendable/with_path.py"); Document doc = new Document(FileUtils.getFileContents(file)); msgs = analyzer.analyzeDocument(nature, (SourceModule) AbstractModule.createModule("extendable.with_path", file, nature, true), prefs, doc, new NullProgressMonitor(), new TestIndentPrefs(true, 4)); printMessages(msgs, 0); } public void testPathFound2() throws IOException, MisconfigurationException { analyzer = new OccurrencesAnalyzer(); File file = new File(TestDependent.TEST_PYSRC_LOC + "extendable/__init__.py"); Document doc = new Document(FileUtils.getFileContents(file)); msgs = analyzer.analyzeDocument(nature, (SourceModule) AbstractModule.createModule("extendable.__init__", file, nature, true), prefs, doc, new NullProgressMonitor(), new TestIndentPrefs(true, 4)); printMessages(msgs, 0); } public void testInitDef() throws IOException { doc = new Document("from extendable import help\n" + "print help.about\n"); checkNoError(); } public void testNoStaticComplain() throws IOException { doc = new Document("class SomeClass(object):\n" + " @staticmethod\n" + " def m1(cls):\n" + " pass\n"); checkNoError(); } public void testNoStaticComplain2() throws IOException { doc = new Document("class SomeClass(object):\n" + " @staticmethod\n" + " def m1():\n" + " pass\n"); checkNoError(); } public void testNoStaticComplain3() throws IOException { doc = new Document("class SomeClass(object):\n" + " @staticmethod\n" + " def m1(self):\n" + " pass\n"); checkNoError(); } public void testInnerAndOuterScopeReference() throws IOException { doc = new Document("EnumType = lambda: EnumType\n" + "print(EnumType())\n"); checkNoError(); } public void testInnerAndOuterScopeReference2() throws IOException { doc = new Document("def m1():\n" + " c = lambda: a\n" + " a = 10\n" + " print c\n" + "\n"); checkNoError(); } public void testAssignNotAcknowledged() throws IOException { doc = new Document("def m1():\n" + " c = object()\n" + " c.x += 1\n" + "\n"); checkNoError(); } public void testNoLeakageInGenerator() throws IOException { doc = new Document("(a for a in range(5))\n" + "print a\n"); checkError(1); } public void testLeakageInListComp() throws IOException { doc = new Document("[b for b in range(5)]\n" + "print b\n"); checkNoError(); } public void testLeakageInListComp2() throws IOException { doc = new Document("[x for x in [y for y in range(3)]]\n" + "print x, y\n"); checkNoError(); } public void testListCompFalsePositive() throws IOException { doc = new Document("alist = []\n" + "blist = []\n" + "clist = [c for c in (a + b for b in blist for a in alist)]\n"); checkNoError(); } public void testParameterAnalysis() throws IOException { doc = new Document("def m1():\n" + " pass\n" + "m1(20)"); IMessage[] messages = checkError(1); assertContainsMsg("m1: arguments don't match", messages); } public void testParameterAnalysis2() throws IOException { doc = new Document("def m1(a):\n" + " pass\n" + "m1()"); IMessage[] messages = checkError(1); assertContainsMsg("m1: arguments don't match", messages); } public void testParameterAnalysis3() throws IOException { doc = new Document("def m1(*args):\n" + " pass\n" + "m1()"); checkNoError(); } public void testParameterAnalysis4() throws IOException { doc = new Document("def m1(**args):\n" + " pass\n" + "m1()"); checkNoError(); } public void testParameterAnalysis5() throws IOException { doc = new Document("def m1(a=10):\n" + " pass\n" + "m1()"); checkNoError(); } public void testParameterAnalysis6() throws IOException { doc = new Document("def m1(a=10):\n" + " pass\n" + "m1(a=20)"); checkNoError(); } public void testParameterAnalysis7() throws IOException { doc = new Document("def m1(a=10):\n" + " pass\n" + "m1(b=20)"); checkError(1); } public void testParameterAnalysis8() throws IOException { doc = new Document("from extendable.calltips.mod1.sub1 import method1\n" + //method1(a, b) "method1(10)"); IMessage[] errors = checkError(1); IMessage msg = errors[0]; assertEquals(msg.getMessage(), "method1: arguments don't match"); assertEquals(msg.getStartCol(doc), 8); assertEquals(msg.getEndCol(doc), 12); assertEquals(msg.getStartLine(doc), 2); assertEquals(msg.getEndLine(doc), 2); } public void testParameterAnalysis8a() throws IOException { doc = new Document("from extendable.calltips.mod1.sub1 import method1\n" + "method1(\n" + " 10)"); IMessage[] errors = checkError(1); IMessage msg = errors[0]; assertEquals(msg.getMessage(), "method1: arguments don't match"); assertEquals(msg.getStartCol(doc), 8); assertEquals(msg.getEndCol(doc), 11); assertEquals(msg.getStartLine(doc), 2); assertEquals(msg.getEndLine(doc), 3); } public void testParameterAnalysis9() throws IOException { doc = new Document("from extendable.calltips.mod1.sub1 import method1\n" + "method1(10, 20)"); checkNoError(); } public void testParameterAnalysis10() throws IOException { doc = new Document("def m1(a):\n" + " pass\n" + "\n" + "d={'a':20}\n" + "m1(**d)"); checkNoError(); } public void testParameterAnalysis11() throws IOException { doc = new Document("def m1(a):\n" + " pass\n" + "\n" + "d=[20]\n" + "m1(*d)"); checkNoError(); } public void testParameterAnalysis12() throws IOException { doc = new Document("def m1(a, **kwargs):\n" + " pass\n" + "\n" + "d=[20]\n" + "m1(10, *d)"); checkError(1); } public void testParameterAnalysis13() throws IOException { doc = new Document("def m1(a, *args):\n" + " pass\n" + "\n" + "d=[20]\n" + "m1(10, *d)"); checkNoError(); } public void testParameterAnalysis14() throws IOException { doc = new Document("def m1(a=10, **args):\n" + " pass\n" + "\n" + "d=[20]\n" + "m1(*d)"); checkNoError(); } public void testParameterAnalysis15() throws IOException { int original = GRAMMAR_TO_USE_FOR_PARSING; GRAMMAR_TO_USE_FOR_PARSING = IPythonNature.GRAMMAR_PYTHON_VERSION_3_0; try { doc = new Document("def w(a=10, *, b):\n" + " pass\n" + "\n" + "w(20, b=10)\n"); checkNoError(); } finally { GRAMMAR_TO_USE_FOR_PARSING = original; } } public void testParameterAnalysis16() throws IOException { int original = GRAMMAR_TO_USE_FOR_PARSING; GRAMMAR_TO_USE_FOR_PARSING = IPythonNature.GRAMMAR_PYTHON_VERSION_3_0; try { doc = new Document("def w(a=10, *, b):\n" + " pass\n" + "\n" + "w(20, 10)\n" //b must be keyword parameter ); checkError(1); } finally { GRAMMAR_TO_USE_FOR_PARSING = original; } } public void testParameterAnalysis17() throws IOException { doc = new Document("class Foo:\n" + " def __init__(self, a):\n" + " pass\n" + "Foo()\n"); checkError(1); } public void testParameterAnalysis17a() throws IOException { doc = new Document("class Foo:\n" + " def __init__(self, a):\n" + " pass\n" + "Foo(10)\n"); checkNoError(); } public void testParameterAnalysis18() throws IOException { doc = new Document("from testOtherImports.f2 import SomeOtherTest\n" + //class with __init__ == __init__(self, a, b) "SomeOtherTest()\n"); checkError("SomeOtherTest: arguments don't match"); } public void testParameterAnalysis19() throws IOException { doc = new Document("from extendable.parameters_check.check import Foo\n" + //class with __init__ == __init__(self, a, b) "foo = Foo(10, 20)\n" + "foo.Method()\n" //Method(self, a) ); checkError("foo.Method: arguments don't match"); } public void testParameterAnalysis19a() throws IOException { doc = new Document("from extendable.parameters_check.check import Foo\n" + //class with __init__ == __init__(self, a, b) "foo = Foo(10, 20)\n" + "Foo.Method(foo, 10)\n" //Method(self, a) ); checkNoError(); } public void testParameterAnalysis19b() throws IOException { doc = new Document("from extendable.parameters_check.check import Foo\n" + //class with __init__ == __init__(self, a, b) "Foo.Method(10)\n" //Method(self, a) ); checkError("Foo.Method: arguments don't match"); } public void testParameterAnalysis19c() throws IOException { doc = new Document("from extendable.parameters_check import Foo\n" + //class with __init__ == __init__(self, a, b) "foo = Foo(10, 20)\n" + "Foo.Method(foo, 10)\n" //Method(self, a) ); checkNoError(); } public void testParameterAnalysis19d() throws IOException { doc = new Document("from extendable.parameters_check import Foo\n" + //class with __init__ == __init__(self, a, b) "foo = Foo(10, 20)\n" + "foo.Method(10)\n" //Method(self, a) ); checkNoError(); } public void testParameterAnalysis19e() throws IOException { doc = new Document("from extendable.parameters_check import Foo\n" + //class with __init__ == __init__(self, a, b) "foo = Foo(10, 20)\n" + "Foo.Method(10)\n" //Method(self, a) ); checkError("Foo.Method: arguments don't match"); } public void testParameterAnalysis19f() throws IOException { doc = new Document("from extendable.parameters_check import Foo\n" + //class with __init__ == __init__(self, a, b) "foo = Foo(10, 20)\n" + "foo.Method(foo, 10)\n" //Method(self, a) ); checkError("foo.Method: arguments don't match"); } public void testParameterAnalysis20() throws IOException { doc = new Document("from extendable.parameters_check.check import Foo\n" + //class with __init__ == __init__(self, a, b) "foo = Foo(10, 20)\n" + "foo.Method(10)\n"); checkNoError(); } public void testParameterAnalysis21() throws IOException { doc = new Document("class Bar(object):\n" + " @classmethod\n" + " def Method(cls, a, b):\n" + " pass\n" + "Bar.Method(10, 20)\n"); checkNoError(); } public void testParameterAnalysis22() throws IOException { doc = new Document("class Bar(object):\n" + " @classmethod\n" + " def Method(cls, a, b):\n" + " pass\n" + "Bar.Method(20)\n"); checkError("Bar.Method: arguments don't match"); } public void testParameterAnalysis23() throws IOException { doc = new Document("class Bar(object):\n" + " def Method(cls, a, b):\n" + " pass\n" + " Method = classmethod(Method)\n" + "Bar.Method(20, 20, 20)\n"); checkError("Bar.Method: arguments don't match"); } public void testParameterAnalysis22a() throws IOException { doc = new Document("class Bar(object):\n" + " @staticmethod\n" + " def Method(cls, a, b):\n" + " pass\n" + "Bar.Method(20, 21)\n"); checkError("Bar.Method: arguments don't match"); } public void testParameterAnalysis23a() throws IOException { doc = new Document("class Bar(object):\n" + " def Method(cls, a, b):\n" + " pass\n" + " Method = staticmethod(Method)\n" + "Bar.Method(20, 20, 20)\n"); checkNoError(); } public void testParameterAnalysis23b() throws IOException { doc = new Document("class Bar(object):\n" + " @staticmethod\n" + " def Method(cls, a, b):\n" + " pass\n" + "Bar.Method(20, 20, 20)\n"); checkNoError(); } public void testParameterAnalysis24() throws IOException { doc = new Document("from extendable.parameters_check import Foo\n" + //class with __init__ == __init__(self, a, b) "\n" + "class X(object):\n" + "\n" + " def __init__(self, a, b):\n" + " Foo.__init__(self, a, b)\n" + "\n" + "\n" + "\n" + "class B(object):\n" + "\n" + " def __init__(self, a, b, c):\n" + " pass\n" + "\n" + " @classmethod\n" + " def Create(cls):\n" + " return B(1, 2, 3)\n"); checkNoError(); } public void testParameterAnalysis24a() throws IOException { doc = new Document("class B(object):\n" + "\n" + " def __init__(self, a, b, c):\n" + " pass\n" + "\n" + " @classmethod\n" + " def Create(cls):\n" + " return B(1, 2)\n"); checkError("B: arguments don't match"); } public void testParameterAnalysis25() throws IOException { doc = new Document("class Bar(object):\n" + "\n" + " def __init__(self):\n" + " pass\n" + "\n" + "class Foo(Bar):\n" + " pass\n" + "\n" + "Foo()\n" + "Foo()\n"); checkNoError(); } public void testParameterAnalysis26() throws IOException { doc = new Document("class Foo(object):\n" + " def Method(self):\n" + " pass\n" + "\n" + " def Method2(self):\n" + " self.Method()\n"); checkNoError(); } public void testParameterAnalysis26a() throws IOException { doc = new Document("class Foo(object):\n" + " def Method(self):\n" + " pass\n" + "\n" + " def Method2(self):\n" + " self.Method(1)\n"); checkError("self.Method: arguments don't match"); } public void testParameterAnalysis27() throws IOException { doc = new Document("class Bounds(object):\n" + "\n" + " def Method(self):\n" + " pass\n" + "\n" + "class Bar(object):\n" + "\n" + " def __init__(self):\n" + " self.bounds = Bounds()\n" + "\n" + " def testGetDiagonalLength(self):\n" + " self.bounds.Method()\n" + "\n"); checkNoError(); } public void testParameterAnalysis27a() throws IOException { doc = new Document("class Bounds(object):\n" + "\n" + " def Method(self):\n" + " pass\n" + "\n" + "class Bar(object):\n" + "\n" + " def __init__(self):\n" + " self.Bounds = Bounds\n" + "\n" + " def testGetDiagonalLength(self):\n" + " self.Bounds.Method()\n" + "\n"); checkError("self.Bounds.Method: arguments don't match"); } List<String> findDefinitionDone = new ArrayList<String>(); private ICallbackListener<ICompletionState> listener = new ICallbackListener<ICompletionState>() { @Override public Object call(ICompletionState obj) { findDefinitionDone.add(obj.getActivationToken()); return null; } }; private void registerOnFindDefinitionListener() { SourceModule.onFindDefinition = new CallbackWithListeners<ICompletionState>(); SourceModule.onFindDefinition.registerListener(listener); } private void unregisterFindDefinitionListener(String... expected) { SourceModule.onFindDefinition = null; if (expected.length != findDefinitionDone.size()) { fail(StringUtils.format( "Expected: %s (%s) find definition call(s). Found: %s (%s)", expected.length, Arrays.asList(expected), findDefinitionDone.size(), findDefinitionDone)); } } public void testParameterAnalysisOptimization() throws IOException { registerOnFindDefinitionListener(); try { doc = new Document("def method():\n" + " \n" + "method()\n" + // "method()\n"); checkNoError(); } finally { unregisterFindDefinitionListener(); } } public void testParameterAnalysisOptimization2() throws IOException { registerOnFindDefinitionListener(); try { doc = new Document("def method():\n" + " \n" + "b = method\n" + "b()\n" + // "b()\n"); checkNoError(); } finally { unregisterFindDefinitionListener(); } } public void testParameterAnalysisOptimization3() throws IOException { registerOnFindDefinitionListener(); try { doc = new Document("class Foo:\n" + " def __init__(self, a):\n" + " pass\n" + "Foo()\n"); checkError("Foo: arguments don't match"); } finally { unregisterFindDefinitionListener(); } } public void testParameterAnalysisOptimization4() throws IOException { registerOnFindDefinitionListener(); try { doc = new Document("class Foo:\n" + " def __init__(self, a):\n" + " pass\n" + "Bar = Foo\n" + "Bar(1)\n"); checkNoError(); } finally { unregisterFindDefinitionListener(); } } public void testParameterAnalysisOptimization5a() throws IOException { registerOnFindDefinitionListener(); try { doc = new Document("from extendable.parameters_check.check import Foo\n" + //class with __init__ == __init__(self, a, b) "foo = Foo(10, 20)\n" + "foo.Method(10)\n"); checkNoError(); } finally { unregisterFindDefinitionListener("Foo", "foo.Method", "foo"); //TODO: This must be improved! } } public void testParameterAnalysisOptimization5() throws IOException { prefs.severityForArgumentsMismatch = IMarker.SEVERITY_INFO; //Nothing will be analyzed and the checks should be skipped! registerOnFindDefinitionListener(); try { doc = new Document("from extendable.parameters_check.check import Foo\n" + //class with __init__ == __init__(self, a, b) "foo = Foo(10, 20, 20)\n" + "foo.Method(10, 30)\n" //error here, but check is disabled! ); checkNoError(); } finally { unregisterFindDefinitionListener(); } } public void testParameterAnalysisOptimization6() throws IOException { registerOnFindDefinitionListener(); try { doc = new Document("from extendable.parameters_check import check\n" + //class with __init__ == __init__(self, a, b) "foo = check.Foo(10, 20, 20)\n" + "foo.Method(10, 20)\n"); checkError("foo.Method: arguments don't match"); } finally { unregisterFindDefinitionListener("", "check.Foo", "foo.Method", "foo"); } } protected Closeable setGrammar(int grammarVersion) { final int initial = GRAMMAR_TO_USE_FOR_PARSING; GRAMMAR_TO_USE_FOR_PARSING = grammarVersion; return new Closeable() { @Override public void close() throws IOException { GRAMMAR_TO_USE_FOR_PARSING = initial; } }; } public void testUsedVariable() throws Exception { try (Closeable x = setGrammar(IPythonNature.GRAMMAR_PYTHON_VERSION_3_0)) { doc = new Document("def foo():\n" + " a = []\n" + " my = [*a]\n" + ""); checkError("Unused variable: my"); } } // public void testNonDefaultAfterDefault() throws IOException{ // doc = new Document( // "def m1(a=20, 20):\n"+ //non-default after default // " pass\n" // ); // checkError(1); // } }