diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes2.properties b/python/helpers/StdlibTypes2.properties similarity index 100% rename from python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes2.properties rename to python/helpers/StdlibTypes2.properties diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes3.properties b/python/helpers/StdlibTypes3.properties similarity index 100% rename from python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes3.properties rename to python/helpers/StdlibTypes3.properties diff --git a/python/helpers/icons/PythonHelpersIcons.java b/python/helpers/icons/PythonHelpersIcons.java new file mode 100644 index 000000000000..c80728d8bc73 --- /dev/null +++ b/python/helpers/icons/PythonHelpersIcons.java @@ -0,0 +1,14 @@ +package icons; + +import com.intellij.openapi.util.IconLoader; + +import javax.swing.*; + +/** + * NOTE THIS FILE IS AUTO-GENERATED by the build/scripts/icons.gant + * Don't repeat mistakes of others ;-) + */ +public class PythonHelpersIcons { + public static final Icon Keybd_closed = IconLoader.getIcon("/coverage/htmlfiles/keybd_closed.png"); // 35x12 + public static final Icon Keybd_open = IconLoader.getIcon("/coverage/htmlfiles/keybd_open.png"); // 35x12 +} diff --git a/python/openapi/src/com/jetbrains/python/psi/WeakFileReference.java b/python/openapi/src/com/jetbrains/python/psi/WeakFileReference.java new file mode 100644 index 000000000000..985835e36731 --- /dev/null +++ b/python/openapi/src/com/jetbrains/python/psi/WeakFileReference.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.psi; + +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet; +import com.jetbrains.python.psi.types.TypeEvalContext; +import org.jetbrains.annotations.Nullable; + +/** + * @author yole + */ +public class WeakFileReference extends FileReference implements PsiReferenceEx { + public WeakFileReference(FileReferenceSet fileReferenceSet, TextRange range, int index, String text) { + super(fileReferenceSet, range, index, text); + } + + @Nullable + @Override + public HighlightSeverity getUnresolvedHighlightSeverity(TypeEvalContext context) { + return HighlightSeverity.WARNING; + } + + @Nullable + @Override + public String getUnresolvedDescription() { + return null; + } +} diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateFileReference.java b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateFileReference.java index 3fb97fc94b8e..c924421a2f6c 100644 --- a/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateFileReference.java +++ b/python/openapi/src/com/jetbrains/python/templateLanguages/TemplateFileReference.java @@ -15,7 +15,6 @@ */ package com.jetbrains.python.templateLanguages; -import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; @@ -26,10 +25,12 @@ import com.intellij.psi.ElementManipulators; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileSystemItem; -import com.intellij.psi.impl.source.resolve.reference.impl.providers.*; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceHelper; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceHelperRegistrar; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.PsiFileSystemItemUtil; import com.intellij.util.IncorrectOperationException; -import com.jetbrains.python.psi.PsiReferenceEx; -import com.jetbrains.python.psi.types.TypeEvalContext; +import com.jetbrains.python.psi.WeakFileReference; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,7 +39,7 @@ import java.util.Collection; /** * @author yole */ -public class TemplateFileReference extends FileReference implements PsiReferenceEx { +public class TemplateFileReference extends WeakFileReference { @NotNull private final FileReferenceSet myReferenceSet; public TemplateFileReference(@NotNull FileReferenceSet fileReferenceSet, TextRange range, int index, String text) { @@ -46,12 +47,6 @@ public class TemplateFileReference extends FileReference implements PsiReference myReferenceSet = fileReferenceSet; } - @Nullable - @Override - public HighlightSeverity getUnresolvedHighlightSeverity(TypeEvalContext context) { - return HighlightSeverity.WARNING; - } - @Nullable @Override public String getUnresolvedDescription() { diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java index 4c90d5077308..1a2ed465955e 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java @@ -1,6 +1,9 @@ package com.jetbrains.python.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiPolyVariantReference; +import com.jetbrains.python.psi.resolve.PyResolveContext; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -27,4 +30,7 @@ public interface PyQualifiedExpression extends PyExpression { */ @Nullable ASTNode getNameElement(); + + @NotNull + PsiPolyVariantReference getReference(PyResolveContext resolveContext); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java index 1dbfa329f11d..c2a6a3597836 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java @@ -30,7 +30,4 @@ public interface PyReferenceExpression extends PyQualifiedExpression, PyReferenc @NotNull PsiPolyVariantReference getReference(); - - @NotNull - PsiPolyVariantReference getReference(PyResolveContext resolveContext); } diff --git a/python/python-helpers.iml b/python/python-helpers.iml index 880a7f9e4113..9d65a5f9a331 100644 --- a/python/python-helpers.iml +++ b/python/python-helpers.iml @@ -7,6 +7,7 @@ + diff --git a/python/rest/src/icons/RestIcons.java b/python/rest/src/icons/RestIcons.java new file mode 100644 index 000000000000..37a8509d1aee --- /dev/null +++ b/python/rest/src/icons/RestIcons.java @@ -0,0 +1,13 @@ +package icons; + +import com.intellij.openapi.util.IconLoader; + +import javax.swing.*; + +/** + * NOTE THIS FILE IS AUTO-GENERATED by the build/scripts/icons.gant + * Don't repeat mistakes of others ;-) + */ +public class RestIcons { + public static final Icon Rst = IconLoader.getIcon("/com/jetbrains/rest/res/rst.png"); // 16x16 +} diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index f4f140dcd059..3920ee02cd5c 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -455,6 +455,7 @@ + diff --git a/python/src/com/jetbrains/python/buildout/BuildoutFacet.java b/python/src/com/jetbrains/python/buildout/BuildoutFacet.java index de5a2ddab2bc..fecbb9ffa70e 100644 --- a/python/src/com/jetbrains/python/buildout/BuildoutFacet.java +++ b/python/src/com/jetbrains/python/buildout/BuildoutFacet.java @@ -97,6 +97,7 @@ public class BuildoutFacet extends Facet implements /** * Generates a sys.path[0:0] = [...] with paths that buildout script wants. + * * @param module to get a buildout facet from * @return the statement, or null if there's no buildout facet. */ @@ -158,7 +159,7 @@ public class BuildoutFacet extends Facet implements } return paths; } - catch(IOException e) { + catch (IOException e) { LOG.info(e); return null; } @@ -208,18 +209,20 @@ public class BuildoutFacet extends Facet implements String text = VfsUtil.loadText(vFile); String[] lines = LineTokenizer.tokenize(text, false); int index = 0; - while(index < lines.length && !lines [index].startsWith("def addsitepackages(")) + while (index < lines.length && !lines[index].startsWith("def addsitepackages(")) { index++; - while(index < lines.length && !lines [index].trim().startsWith("buildout_paths = [")) + } + while (index < lines.length && !lines[index].trim().startsWith("buildout_paths = [")) { index++; + } index++; - while(index < lines.length && !lines [index].trim().equals("]")) { - String line = lines [index].trim(); + while (index < lines.length && !lines[index].trim().equals("]")) { + String line = lines[index].trim(); if (line.endsWith(",")) { - line = line.substring(0, line.length()-1); + line = line.substring(0, line.length() - 1); } if (line.startsWith("'") && line.endsWith("'")) { - result.add(StringUtil.unescapeStringCharacters(line.substring(1, line.length()-1))); + result.add(StringUtil.unescapeStringCharacters(line.substring(1, line.length() - 1))); } index++; } @@ -243,10 +246,12 @@ public class BuildoutFacet extends Facet implements // alter execution script ParamsGroup script_params = params.getParamsGroup(PythonCommandLineState.GROUP_SCRIPT); assert script_params != null; - String normal_script = script_params.getParameters().get(0); // expect DjangoUtil.MANAGE_FILE - String engulfer_path = PythonHelpersLocator.getHelperPath("pycharm/buildout_engulfer.py"); - new_env.put("PYCHARM_ENGULF_SCRIPT", getConfiguration().getScriptName()); - script_params.getParametersList().replaceOrPrepend(normal_script, engulfer_path); + if (script_params.getParameters().size() > 0) { + String normal_script = script_params.getParameters().get(0); // expect DjangoUtil.MANAGE_FILE + String engulfer_path = PythonHelpersLocator.getHelperPath("pycharm/buildout_engulfer.py"); + new_env.put("PYCHARM_ENGULF_SCRIPT", getConfiguration().getScriptName()); + script_params.getParametersList().replaceOrPrepend(normal_script, engulfer_path); + } // add pycharm helpers to pythonpath so that fixGetpass is importable PythonEnvUtil.addToPythonPath(new_env, PythonHelpersLocator.getHelpersRoot().getAbsolutePath()); @@ -280,7 +285,7 @@ public class BuildoutFacet extends Facet implements String text = FileUtil.loadFile(cfg); final PsiFile configFile = PsiFileFactory .getInstance(getModule().getProject()).createFileFromText("buildout.cfg", - BuildoutCfgLanguage.INSTANCE, text); + BuildoutCfgLanguage.INSTANCE, text); if (configFile != null && configFile instanceof BuildoutCfgFile) { return (BuildoutCfgFile)configFile; } @@ -290,7 +295,7 @@ public class BuildoutFacet extends Facet implements } return null; } - + public static List getScripts(@Nullable BuildoutFacet buildoutFacet, final VirtualFile baseDir) { File rootPath = null; if (buildoutFacet != null) { diff --git a/python/src/com/jetbrains/python/buildout/config/BuildoutCfgProblemFileHighlightFilter.java b/python/src/com/jetbrains/python/buildout/config/BuildoutCfgProblemFileHighlightFilter.java index 41b1afb7455b..ae20d7b4f65a 100644 --- a/python/src/com/jetbrains/python/buildout/config/BuildoutCfgProblemFileHighlightFilter.java +++ b/python/src/com/jetbrains/python/buildout/config/BuildoutCfgProblemFileHighlightFilter.java @@ -1,7 +1,6 @@ package com.jetbrains.python.buildout.config; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; diff --git a/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java b/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java index 75056b874fce..3c24ee89fe3e 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java +++ b/python/src/com/jetbrains/python/codeInsight/PyTargetElementEvaluator.java @@ -6,9 +6,11 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; +import com.jetbrains.python.psi.PyParameter; +import com.jetbrains.python.psi.PyQualifiedExpression; import com.jetbrains.python.psi.PyReferenceExpression; +import com.jetbrains.python.psi.PyTargetExpression; import com.jetbrains.python.psi.resolve.PyResolveContext; -import com.jetbrains.python.psi.resolve.QualifiedResolveResult; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -29,12 +31,15 @@ public class PyTargetElementEvaluator implements TargetElementEvaluator { } final PsiElement element = ref.getElement(); PsiElement result = ref.resolve(); - if (result instanceof PyReferenceExpression && - PsiTreeUtil.getParentOfType(element, ScopeOwner.class) == PsiTreeUtil.getParentOfType(result, ScopeOwner.class)) { - QualifiedResolveResult resolveResult = ((PyReferenceExpression)result).followAssignmentsChain(PyResolveContext.noImplicits()); - PsiElement finalResult = resolveResult.getElement(); - if (PsiTreeUtil.getParentOfType(element, ScopeOwner.class) == PsiTreeUtil.getParentOfType(finalResult, ScopeOwner.class)) { - return finalResult; + while (result instanceof PyReferenceExpression || result instanceof PyTargetExpression) { + PsiElement nextResult = ((PyQualifiedExpression) result).getReference(PyResolveContext.noImplicits()).resolve(); + if (nextResult != null && nextResult != result && + PsiTreeUtil.getParentOfType(element, ScopeOwner.class) == PsiTreeUtil.getParentOfType(result, ScopeOwner.class) && + (nextResult instanceof PyReferenceExpression || nextResult instanceof PyTargetExpression || nextResult instanceof PyParameter)) { + result = nextResult; + } + else { + break; } } return result; diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java index 7d750beaf938..ac303b484ffb 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java @@ -6,6 +6,7 @@ import com.intellij.codeInsight.lookup.TailTypeDecorator; import com.intellij.lang.ASTNode; import com.intellij.openapi.editor.Document; import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PatternCondition; import com.intellij.patterns.PsiElementPattern; import com.intellij.patterns.StandardPatterns; import com.intellij.psi.*; @@ -50,12 +51,12 @@ public class PyKeywordCompletionContributor extends CompletionContributor { final ASTNode ctxNode = context.getNode(); if (ctxNode != null && PyTokenTypes.STRING_NODES.contains(ctxNode.getElementType())) return false; // no sense inside string PsiElement p = (PsiElement)element; - int first_offset = p.getTextOffset(); + int firstOffset = p.getTextRange().getStartOffset(); // we must be a stmt ourselves, not a part of another stmt // try to climb to the stmt level with the same offset while (true) { if (p == null) return false; - if (p.getTextOffset() != first_offset) return false; + if (p.getTextRange().getStartOffset() != firstOffset) return false; if (p instanceof PyStatement) break; p = p.getParent(); } @@ -72,7 +73,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor { PsiDocumentManager docMgr = PsiDocumentManager.getInstance(p.getProject()); Document doc = docMgr.getDocument(p.getContainingFile().getOriginalFile()); if (doc != null) { - if (doc.getLineNumber(prev.getTextRange().getEndOffset()) == doc.getLineNumber(first_offset)) { + if (doc.getLineNumber(prev.getTextRange().getEndOffset()) == doc.getLineNumber(firstOffset)) { return false; // same line } } @@ -214,6 +215,9 @@ public class PyKeywordCompletionContributor extends CompletionContributor { private static final PsiElementPattern.Capture IN_STRING_LITERAL = psiElement().inside(PyStringLiteralExpression.class); + private static final PsiElementPattern.Capture IN_FUNCTION_HEADER = + psiElement().inside(PyFunction.class).andNot(psiElement().inside(PyStatementList.class)); + public static final PsiElementPattern.Capture AFTER_QUALIFIER = psiElement().afterLeaf(psiElement().withText(".").inside(PyReferenceExpression.class)); @@ -229,12 +233,13 @@ public class PyKeywordCompletionContributor extends CompletionContributor { psiElement().withElementType(PyTokenTypes.DOT)) ).inside(PyFromImportStatement.class); - private static final PsiElementPattern.Capture IN_WITH_AFTER_REF = - psiElement().afterLeaf(psiElement() - .withElementType(PyTokenTypes.IDENTIFIER) - .inside(PyReferenceExpression.class) - .inside(PyWithStatement.class) - ); + public static final ElementPattern IN_WITH_AFTER_REF = + psiElement().afterLeaf(psiElement().inside(psiElement(PyWithItem.class).with(new PatternCondition("withoutAsKeyword") { + @Override + public boolean accepts(@NotNull PyWithItem item, ProcessingContext context) { + return item.getNode().findChildByType(PyTokenTypes.AS_KEYWORD) == null; + } + }))); private static final PsiElementPattern.Capture IN_EXCEPT_AFTER_REF = psiElement().afterLeaf(psiElement() @@ -509,6 +514,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor { .andNot(IN_COMMENT) .andNot(IN_IMPORT_STMT) .andNot(IN_PARAM_LIST) + .andNot(IN_FUNCTION_HEADER) .andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL) , new PyKeywordCompletionProvider("not", "lambda") @@ -524,6 +530,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor { .andNot(IN_IMPORT_STMT) .and(NOT_PARAMETER_OR_DEFAULT_VALUE) .andNot(AFTER_QUALIFIER) + .andNot(IN_FUNCTION_HEADER) , new PyKeywordCompletionProvider(TailType.NONE, "True", "False", "None") ); diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index 1bcda3178fcf..4e03bd564f9e 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -5,6 +5,7 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.jetbrains.python.PyNames; +import com.jetbrains.python.PythonHelpersLocator; import com.jetbrains.python.documentation.StructuredDocString; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; @@ -15,6 +16,7 @@ import com.jetbrains.python.psi.types.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Map; @@ -249,7 +251,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { final String name = level.isPy3K() ? "StdlibTypes3" : "StdlibTypes2"; if (result.isEmpty()) { try { - final InputStream s = getClass().getResourceAsStream(String.format("%s.properties", name)); + final InputStream s = new FileInputStream(PythonHelpersLocator.getHelperFile(String.format("%s.properties", name))); try { result.load(s); } diff --git a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java index 61e65cae5f51..e7dbfd93992b 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java @@ -221,7 +221,7 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl lock.wait(10); } catch (InterruptedException e) { - LOG.error(e); + //pass } } } diff --git a/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java b/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java index 3bdadd9d57c4..b681d334cfea 100644 --- a/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java +++ b/python/src/com/jetbrains/python/debugger/PyClassTreeChooserDialog.java @@ -17,11 +17,9 @@ import java.util.List; * @author traff */ public class PyClassTreeChooserDialog extends AbstractTreeClassChooserDialog{ - public PyClassTreeChooserDialog(String title, - Project project, - GlobalSearchScope scope, - @Nullable Filter classFilter, @Nullable PyClass initialClass) { - super(title, project, scope, classFilter, initialClass); + public PyClassTreeChooserDialog(String title, Project project, GlobalSearchScope scope, @Nullable Filter classFilter, + @Nullable PyClass initialClass) { + super(title, project, scope, PyClass.class, classFilter, initialClass); } @NotNull diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index 2210d8a59b32..46cdc7480740 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -38,10 +38,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.net.ServerSocket; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import static javax.swing.SwingUtilities.invokeLater; @@ -61,7 +58,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr private final Map> myRegisteredExceptionBreakpoints = new ConcurrentHashMap>(); - private final List mySuspendedThreads = Lists.newArrayList(); + private final List mySuspendedThreads = Collections.synchronizedList(Lists.newArrayList()); private final Map myStackFrameCache = Maps.newHashMap(); private final Map myNewVariableValue = Maps.newHashMap(); diff --git a/python/src/com/jetbrains/python/debugger/PyDebuggerEditorsProvider.java b/python/src/com/jetbrains/python/debugger/PyDebuggerEditorsProvider.java index ba1fc8754f5d..e1b47b2285fa 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebuggerEditorsProvider.java +++ b/python/src/com/jetbrains/python/debugger/PyDebuggerEditorsProvider.java @@ -46,15 +46,17 @@ public class PyDebuggerEditorsProvider extends XDebuggerEditorsProvider { final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document); if (psiFile != null) { int offset = sourcePosition.getOffset(); - final int lineEndOffset = document.getLineEndOffset(document.getLineNumber(offset)); - do { - PsiElement element = psiFile.findElementAt(offset); - if (element != null && !(element instanceof PsiWhiteSpace || element instanceof PsiComment)) { - return PyPsiUtils.getStatement(element); + if (offset >= 0 && offset < document.getTextLength()) { + final int lineEndOffset = document.getLineEndOffset(document.getLineNumber(offset)); + do { + PsiElement element = psiFile.findElementAt(offset); + if (element != null && !(element instanceof PsiWhiteSpace || element instanceof PsiComment)) { + return PyPsiUtils.getStatement(element); + } + offset = element.getTextRange().getEndOffset() + 1; } - offset = element.getTextRange().getEndOffset() + 1; + while (offset < lineEndOffset); } - while (offset < lineEndOffset); } } return null; diff --git a/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java b/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java index 009811ab0b2d..ac51515a5e33 100644 --- a/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java +++ b/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java @@ -141,7 +141,7 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { try { data = CALL_SIGNATURES_ATTRIBUTE.readAttributeBytes(file); } - catch (IOException e) { + catch (Exception e) { data = null; } diff --git a/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java b/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java index 87bd5e09efe3..7210f6493bbc 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java +++ b/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java @@ -8,6 +8,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ProcessingContext; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.PyDocStringOwner; +import com.jetbrains.python.psi.PyImportElement; import com.jetbrains.python.psi.PyStringLiteralExpression; import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl; import com.jetbrains.python.psi.types.PyType; @@ -85,7 +86,7 @@ public class DocStringReferenceProvider extends PsiReferenceProvider { final PyTypeParser.ParseResult parseResult = PyTypeParser.parse(anchor, s.toString()); final Map types = parseResult.getTypes(); if (types.isEmpty()) { - result.add(new DocStringTypeReference(anchor, s.getTextRange().shiftRight(offset), s.getTextRange().shiftRight(offset), null)); + result.add(new DocStringTypeReference(anchor, s.getTextRange().shiftRight(offset), s.getTextRange().shiftRight(offset), null, null)); } offset = s.getTextRange().getStartOffset() + offset; final Map fullRanges = parseResult.getFullRanges(); @@ -93,7 +94,8 @@ public class DocStringReferenceProvider extends PsiReferenceProvider { final PyType t = pair.getValue(); final TextRange range = pair.getKey().shiftRight(offset); final TextRange fullRange = fullRanges.containsKey(t) ? fullRanges.get(t).shiftRight(offset) : range; - result.add(new DocStringTypeReference(anchor, range, fullRange, t)); + final PyImportElement importElement = parseResult.getImports().get(t); + result.add(new DocStringTypeReference(anchor, range, fullRange, t, importElement)); } return result; } diff --git a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java index f783e274219b..c005ced7c2b8 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java +++ b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java @@ -6,29 +6,36 @@ import com.intellij.psi.*; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.PyImportedModule; import com.jetbrains.python.psi.impl.PyQualifiedName; +import com.jetbrains.python.psi.impl.ResolveResultList; +import com.jetbrains.python.psi.resolve.ImportedResolveResult; import com.jetbrains.python.psi.resolve.QualifiedNameFinder; +import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.types.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** * User : catherine */ -public class DocStringTypeReference extends PsiReferenceBase { - private PyType myType; - private TextRange myFullRange; +public class DocStringTypeReference extends PsiPolyVariantReferenceBase { + @Nullable private PyType myType; + @NotNull private TextRange myFullRange; + @Nullable private final PyImportElement myImportElement; - public DocStringTypeReference(PsiElement element, TextRange range, TextRange fullRange, @Nullable PyType type) { + public DocStringTypeReference(PsiElement element, TextRange range, @NotNull TextRange fullRange, @Nullable PyType type, + @Nullable PyImportElement importElement) { super(element, range); myFullRange = fullRange; myType = type; + myImportElement = importElement; } + @Nullable @Override public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { if (element.equals(resolve())) { @@ -49,7 +56,7 @@ public class DocStringTypeReference extends PsiReferenceBase { } public boolean isSoft() { - return true; + return false; } @Override @@ -68,16 +75,28 @@ public class DocStringTypeReference extends PsiReferenceBase { return super.isReferenceTo(element); } - @Nullable - public PsiElement resolve() { + @NotNull + @Override + public ResolveResult[] multiResolve(boolean incompleteCode) { + PsiElement result = null; + final ResolveResultList results = new ResolveResultList(); if (myType instanceof PyClassType) { - return ((PyClassType)myType).getPyClass(); + result = ((PyClassType)myType).getPyClass(); } - if (myType instanceof PyImportedModuleType) { - final PyImportedModule module = ((PyImportedModuleType)myType).getImportedModule(); - return module.resolve(); + else if (myType instanceof PyImportedModuleType) { + result = ((PyImportedModuleType)myType).getImportedModule().resolve(); } - return null; + if (result != null) { + if (myImportElement != null) { + results.add(new ImportedResolveResult(result, + RatedResolveResult.RATE_NORMAL, + Collections.singletonList(myImportElement))); + } + else { + results.poke(result, RatedResolveResult.RATE_NORMAL); + } + } + return results.toArray(new ResolveResult[0]); } @NotNull diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index 25623b87c981..12b81ea4f41d 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -36,6 +36,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.HashMap; @@ -385,16 +386,22 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i } private static boolean pageExists(String url) { + if (new File(url).exists()) { + return true; + } HttpClient client = new HttpClient(); client.setTimeout(5 * 1000); client.setConnectionTimeout(5 * 1000); - HeadMethod method = new HeadMethod(url); try { + HeadMethod method = new HeadMethod(url); int rc = client.executeMethod(method); if (rc == 404) { return false; } } + catch (IllegalArgumentException e) { + return false; + } catch (IOException ignored) { } return true; diff --git a/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java b/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java index 934cdab8df82..622c87e3bdb5 100644 --- a/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java +++ b/python/src/com/jetbrains/python/findUsages/PyFindUsagesHandlerFactory.java @@ -4,12 +4,16 @@ import com.intellij.find.findUsages.FindUsagesHandler; import com.intellij.find.findUsages.FindUsagesHandlerFactory; import com.intellij.openapi.ui.Messages; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFileSystemItem; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyFunction; +import com.jetbrains.python.psi.PyUtil; +import com.jetbrains.python.psi.impl.PyImportedModule; import com.jetbrains.python.psi.search.PySuperMethodsSearch; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -22,14 +26,22 @@ public class PyFindUsagesHandlerFactory extends FindUsagesHandlerFactory { @Override public boolean canFindUsages(@NotNull PsiElement element) { return element instanceof PyClass || - (element instanceof PyFile && PyNames.INIT_DOT_PY.equals(((PyFile) element).getName())) || + (element instanceof PyFile && PyUtil.isPackage((PyFile)element)) || + element instanceof PyImportedModule || element instanceof PyFunction; } + @Nullable @Override public FindUsagesHandler createFindUsagesHandler(@NotNull PsiElement element, boolean forHighlightUsages) { - if (element instanceof PyFile) { - return new PyModuleFindUsagesHandler((PyFile) element); + if (element instanceof PyImportedModule) { + final PsiElement resolved = ((PyImportedModule)element).resolve(); + if (resolved != null) { + element = resolved; + } + } + if (element instanceof PsiFileSystemItem) { + return new PyModuleFindUsagesHandler((PsiFileSystemItem)element); } if (element instanceof PyFunction) { if (!forHighlightUsages) { @@ -60,7 +72,10 @@ public class PyFindUsagesHandlerFactory extends FindUsagesHandlerFactory { } return new PyFunctionFindUsagesHandler(element); } - return new PyClassFindUsagesHandler((PyClass)element); + if (element instanceof PyClass) { + return new PyClassFindUsagesHandler((PyClass)element); + } + return null; } private static boolean isInClassobj(PyFunction fun) { diff --git a/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.java b/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.java index 61955046dc30..9441948095bb 100644 --- a/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.java +++ b/python/src/com/jetbrains/python/findUsages/PyModuleFindUsagesHandler.java @@ -8,7 +8,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFileSystemItem; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; -import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyUtil; import org.jetbrains.annotations.NotNull; @@ -18,7 +17,7 @@ import org.jetbrains.annotations.NotNull; public class PyModuleFindUsagesHandler extends FindUsagesHandler { private final PsiFileSystemItem myElement; - protected PyModuleFindUsagesHandler(@NotNull PyFile file) { + protected PyModuleFindUsagesHandler(@NotNull PsiFileSystemItem file) { super(file); final PsiElement e = PyUtil.turnInitIntoDir(file); myElement = e instanceof PsiFileSystemItem ? (PsiFileSystemItem)e : file; diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index 219e21aa3459..03dab57430dc 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -39,6 +39,7 @@ import com.jetbrains.python.codeInsight.imports.OptimizeImportsQuickFix; import com.jetbrains.python.codeInsight.imports.PythonReferenceImporter; import com.jetbrains.python.console.PydevConsoleRunner; import com.jetbrains.python.documentation.DocStringParameterReference; +import com.jetbrains.python.documentation.DocStringTypeReference; import com.jetbrains.python.packaging.PyPIPackageUtil; import com.jetbrains.python.packaging.PyPackageManager; import com.jetbrains.python.packaging.PyRequirement; @@ -366,6 +367,9 @@ public class PyUnresolvedReferencesInspection extends PyInspection { private void registerUnresolvedReferenceProblem(@NotNull PyElement node, @NotNull PsiReference reference, @NotNull HighlightSeverity severity) { + if (reference instanceof DocStringTypeReference) { + return; + } String description = null; final String text = reference.getElement().getText(); TextRange rangeInElement = reference.getRangeInElement(); diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 7cd8ea4f44bc..d9875cf384ad 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -361,23 +361,6 @@ public class PyUtil { return superClasses; } - /** - * Finds the first identifier AST node under target element, and returns its text. - * - * @param target - * @return identifier text, or null. - */ - public static - @Nullable - String getIdentifier(PsiElement target) { - ASTNode node = target.getNode(); - if (node != null) { - ASTNode ident_node = node.findChildByType(PyTokenTypes.IDENTIFIER); - if (ident_node != null) return ident_node.getText(); - } - return null; - } - // TODO: move to a more proper place? @@ -392,16 +375,16 @@ public class PyUtil { if (ref != null) { PyExpression qualifier = ref.getQualifier(); if (qualifier != null) { - String attr_name = getIdentifier(ref); - if ("__class__".equals(attr_name)) { - PyType qual_type = context.getType(qualifier); - if (qual_type instanceof PyClassType) { - return new PyClassTypeImpl(((PyClassType)qual_type).getPyClass(), true); // always as class, never instance + String attr_name = ref.getReferencedName(); + if (PyNames.CLASS.equals(attr_name)) { + PyType qualifierType = context.getType(qualifier); + if (qualifierType instanceof PyClassType) { + return new PyClassTypeImpl(((PyClassType)qualifierType).getPyClass(), true); // always as class, never instance } } - else if ("__dict__".equals(attr_name)) { - PyType qual_type = context.getType(qualifier); - if (qual_type instanceof PyClassType && ((PyClassType)qual_type).isDefinition()) { + else if (PyNames.DICT.equals(attr_name)) { + PyType qualifierType = context.getType(qualifier); + if (qualifierType instanceof PyClassType && ((PyClassType)qualifierType).isDefinition()) { return PyBuiltinCache.getInstance(ref).getDictType(); } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java index a82c317016ac..4a387ce3392b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java @@ -4,7 +4,6 @@ import com.intellij.lang.ASTNode; import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.stubs.IStubElementType; @@ -202,11 +201,7 @@ public class PyImportElementImpl extends PyBaseElementImpl } if (qName.getComponentCount() == 1) { if (resolveImportElement) { - final PsiElement element = ResolveImportUtil.resolveImportElement(this, PyQualifiedName.fromComponents(name)); - if (element instanceof PsiDirectory) { - return createImportedModule(name); - } - return element; + return ResolveImportUtil.resolveImportElement(this, PyQualifiedName.fromComponents(name)); } return this; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java b/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java index 1716ce244be2..38b8ade0769b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java +++ b/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java @@ -134,7 +134,9 @@ public class PyImportedModule extends LightElement implements NameDefiner { @Nullable private static PsiElement resolve(PyImportElement importElement, @NotNull final PyQualifiedName prefix) { - return PyUtil.turnDirIntoInit(ResolveImportUtil.resolveImportElement(importElement, prefix)); + final PsiElement resolved = ResolveImportUtil.resolveImportElement(importElement, prefix); + final PsiElement packageInit = PyUtil.turnDirIntoInit(resolved); + return packageInit != null ? packageInit : resolved; } public boolean isAncestorOf(PyImportedModule other) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index eafcb179fd1f..0a227454c8c1 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -5,6 +5,7 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiReference; import com.intellij.psi.ResolveResult; import com.intellij.psi.search.GlobalSearchScope; @@ -481,10 +482,15 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl types = new HashMap(); final Map fullRanges = new HashMap(); - final PyType t = parse(anchor, type, types, fullRanges, 0); - return new ParseResult(t, types, fullRanges); + final Map imports = new HashMap(); + final PyType t = parse(anchor, type, types, fullRanges, imports, 0); + return new ParseResult(t, types, fullRanges, imports); } public static class ParseResult { @Nullable private PyType myType; @NotNull private Map myTypes; @NotNull private Map myFullRanges; + @NotNull private final Map myImports; - ParseResult(@Nullable PyType type, @NotNull Map types, @NotNull Map fullRanges) { + ParseResult(@Nullable PyType type, @NotNull Map types, @NotNull Map fullRanges, + @NotNull Map imports) { myType = type; myTypes = types; myFullRanges = fullRanges; + myImports = imports; } @Nullable @@ -69,11 +73,16 @@ public class PyTypeParser { public Map getFullRanges() { return myFullRanges; } + + @NotNull + public Map getImports() { + return myImports; + } } @Nullable private static PyType parse(@Nullable PsiElement anchor, @NotNull String type, @NotNull Map types, - @NotNull Map fullRanges, int offset) { + @NotNull Map fullRanges, @NotNull Map imports, int offset) { if (anchor == null || !anchor.isValid()) { return null; } @@ -87,10 +96,10 @@ public class PyTypeParser { return t; } if (type.startsWith("(") && type.endsWith(")")) { - return parseTupleType(anchor, type.substring(1, type.length() - 1), types, fullRanges, offset + 1); + return parseTupleType(anchor, type.substring(1, type.length() - 1), types, fullRanges, imports, offset + 1); } if (type.contains(" or ")) { - return parseUnionType(anchor, type, types, fullRanges, offset); + return parseUnionType(anchor, type, types, fullRanges, imports, offset); } final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(anchor); if (type.equals("unknown")) { @@ -132,7 +141,7 @@ public class PyTypeParser { return t; } if (type.startsWith("dict from")) { - return parseDictFromToType(anchor, type, types, fullRanges, offset); + return parseDictFromToType(anchor, type, types, fullRanges, imports, offset); } if (type.equals("integer") || (type.equals("long") && LanguageLevel.forElement(anchor).isPy3K())) { final PyType t = builtinCache.getIntType(); @@ -144,8 +153,8 @@ public class PyTypeParser { } final Matcher m = PARAMETRIZED_CLASS.matcher(type); if (m.matches()) { - final PyType objType = parseObjectType(anchor, m.group(1), builtinCache, types, fullRanges, offset + m.start(1)); - final PyType elementType = parse(anchor, m.group(2), types, fullRanges, offset + m.start(2)); + final PyType objType = parseObjectType(anchor, m.group(1), builtinCache, types, fullRanges, imports, offset + m.start(1)); + final PyType elementType = parse(anchor, m.group(2), types, fullRanges, imports, offset + m.start(2)); if (objType != null) { if (objType instanceof PyClassType && elementType != null) { return new PyCollectionTypeImpl(((PyClassType)objType).getPyClass(), false, elementType); @@ -153,12 +162,13 @@ public class PyTypeParser { return objType; } } - return parseObjectType(anchor, type, builtinCache, types, fullRanges, offset); + return parseObjectType(anchor, type, builtinCache, types, fullRanges, imports, offset); } @Nullable private static PyType parseObjectType(@NotNull PsiElement anchor, @NotNull String type, @NotNull PyBuiltinCache builtinCache, - @NotNull Map types, @NotNull Map fullRanges, int offset) { + @NotNull Map types, @NotNull Map fullRanges, + @NotNull Map imports, int offset) { final TextRange whole = new TextRange(offset, offset + type.length()); final PyClassType classType = builtinCache.getObjectType(type); if (classType != null) { @@ -170,6 +180,7 @@ public class PyTypeParser { final PyClass aClass = ((PyFile)anchorFile).findTopLevelClass(type); if (aClass != null) { final PyType t = new PyClassTypeImpl(aClass, false); + t.assertValid("PyFile.findTopLevelClass()"); types.put(whole, t); return t; } @@ -187,6 +198,7 @@ public class PyTypeParser { final PyType pyType = getTypeFromQName(anchor, qName, whole, unusedRanges, fullRanges, offset); if (pyType != null) { types.put(whole, pyType); + imports.put(pyType, element); return pyType; } } @@ -199,6 +211,7 @@ public class PyTypeParser { final Collection classes = PyClassNameIndex.find(type, anchor.getProject(), true); if (classes.size() == 1) { final PyType t = new PyClassTypeImpl(classes.iterator().next(), false); + t.assertValid("PyClassNameIndex.find().iterator().next()"); types.put(whole, t); return t; } @@ -237,9 +250,12 @@ public class PyTypeParser { if (t instanceof PyClassType) { t = ((PyClassType)t).toInstance(); } - types.put(classRange.shiftRight(offset), t); - fullRanges.put(t, whole); - return t; + if (t != null) { + t.assertValid("PyImportedModuleType.resolveMember()"); + types.put(classRange.shiftRight(offset), t); + fullRanges.put(t, whole); + return t; + } } } } @@ -247,6 +263,7 @@ public class PyTypeParser { for (PyClass aClass : classes) { if (qName.equals(aClass.getQualifiedName())) { final PyType t = new PyClassTypeImpl(aClass, false); + t.assertValid("PyClassNameIndex.find()"); types.put(classRange.shiftRight(offset), t); fullRanges.put(t, whole); return t; @@ -257,6 +274,7 @@ public class PyTypeParser { final String name = aClass.getQualifiedName(); if (name != null && name.startsWith("_")) { final PyType t = new PyClassTypeImpl(aClass, false); + t.assertValid("PyClassNameIndex.find() for _foo"); types.put(classRange.shiftRight(offset), t); fullRanges.put(t, whole); return t; @@ -268,24 +286,26 @@ public class PyTypeParser { @Nullable private static PyType parseTupleType(@NotNull PsiElement anchor, @NotNull String elementTypeNames, @NotNull Map types, - @NotNull Map fullRanges, int offset) { + @NotNull Map fullRanges, @NotNull Map imports, + int offset) { final List ranges = splitRanges(elementTypeNames, ","); final List elementTypes = new ArrayList(); for (TextRange range : ranges) { - elementTypes.add(parse(anchor, range.substring(elementTypeNames), types, fullRanges, offset + range.getStartOffset())); + elementTypes.add(parse(anchor, range.substring(elementTypeNames), types, fullRanges, imports, offset + range.getStartOffset())); } return PyTupleType.create(anchor, elementTypes.toArray(new PyType[elementTypes.size()])); } @Nullable private static PyType parseDictFromToType(@NotNull PsiElement anchor, @NotNull String type, @NotNull Map types, - @NotNull Map fullRanges, int offset) { + @NotNull Map fullRanges, @NotNull Map imports, + int offset) { final Matcher m = DICT_TYPE.matcher(type); PyClassType dict = PyBuiltinCache.getInstance(anchor).getDictType(); if (dict != null) { if (m.matches()) { - PyType from = parse(anchor, m.group(1), types, fullRanges, offset + m.start(1)); - PyType to = parse(anchor, m.group(2), types, fullRanges, offset + m.start(2)); + PyType from = parse(anchor, m.group(1), types, fullRanges, imports, offset + m.start(1)); + PyType to = parse(anchor, m.group(2), types, fullRanges, imports, offset + m.start(2)); final PyType p = PyTupleType.create(anchor, new PyType[] {from, to}); return new PyCollectionTypeImpl(dict.getPyClass(), false, p); } @@ -296,11 +316,12 @@ public class PyTypeParser { @Nullable private static PyType parseUnionType(@NotNull PsiElement anchor, @NotNull String type, @NotNull Map types, - @NotNull Map fullRanges, int offset) { + @NotNull Map fullRanges, @NotNull Map imports, + int offset) { final List ranges = splitRanges(type, " or "); PyType result = null; for (TextRange range : ranges) { - final PyType t = parse(anchor, range.substring(type), types, fullRanges, offset + range.getStartOffset()); + final PyType t = parse(anchor, range.substring(type), types, fullRanges, imports, offset + range.getStartOffset()); result = (result == null) ? t : PyUnionType.union(result, t); } return result; diff --git a/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java b/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java index 64b22c1785ae..ccbf403fdc40 100644 --- a/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java +++ b/python/src/com/jetbrains/python/sdk/PySkeletonGenerator.java @@ -199,7 +199,7 @@ public class PySkeletonGenerator { return new ListBinariesResult(generatorVersion, binaries); } - public boolean deleteOrLog(File item) { + public boolean deleteOrLog(@NotNull File item) { boolean deleted = item.delete(); if (!deleted) LOG.warn("Failed to delete skeleton file " + item.getAbsolutePath()); return deleted; diff --git a/python/testData/completion/dunderClass.after.py b/python/testData/completion/dunderClass.after.py new file mode 100644 index 000000000000..aaaffce5f04b --- /dev/null +++ b/python/testData/completion/dunderClass.after.py @@ -0,0 +1,4 @@ +class Foo(object): + xyzzy = 3 + def fun(self): + a = self.__class__.xyzzy \ No newline at end of file diff --git a/python/testData/completion/dunderClass.py b/python/testData/completion/dunderClass.py new file mode 100644 index 000000000000..4d1a9136ac59 --- /dev/null +++ b/python/testData/completion/dunderClass.py @@ -0,0 +1,4 @@ +class Foo(object): + xyzzy = 3 + def fun(self): + a = self.__class__.x \ No newline at end of file diff --git a/python/testData/findUsages/NamespacePackageUsages/a.py b/python/testData/findUsages/NamespacePackageUsages/a.py new file mode 100644 index 000000000000..79cdd72a726c --- /dev/null +++ b/python/testData/findUsages/NamespacePackageUsages/a.py @@ -0,0 +1,3 @@ +import nspkg1.m1 + +print(nspkg1) \ No newline at end of file diff --git a/python/testData/findUsages/NamespacePackageUsages/b.py b/python/testData/findUsages/NamespacePackageUsages/b.py new file mode 100644 index 000000000000..9b2491c9488f --- /dev/null +++ b/python/testData/findUsages/NamespacePackageUsages/b.py @@ -0,0 +1 @@ +import nspkg1 \ No newline at end of file diff --git a/python/testData/findUsages/NamespacePackageUsages/nspkg1/m1.py b/python/testData/findUsages/NamespacePackageUsages/nspkg1/m1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/importUsedInDocString.py b/python/testData/inspections/PyUnresolvedReferencesInspection/importUsedInDocString.py new file mode 100644 index 000000000000..af34c174f899 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/importUsedInDocString.py @@ -0,0 +1,7 @@ +from datetime import timedelta #pass + +def f(d): + """ + :type d: timedelta or int + """ + pass diff --git a/python/testData/refactoring/rename/renameReassignedParameter.py b/python/testData/refactoring/rename/renameReassignedParameter.py new file mode 100644 index 000000000000..0bcbbb4fb5ef --- /dev/null +++ b/python/testData/refactoring/rename/renameReassignedParameter.py @@ -0,0 +1,6 @@ +def cover(a, lab=1): + item = a + lab + lab = 1 + if a > 1: + lab = cover(item, lab) + return lab \ No newline at end of file diff --git a/python/testData/refactoring/rename/renameReassignedParameter_after.py b/python/testData/refactoring/rename/renameReassignedParameter_after.py new file mode 100644 index 000000000000..cb790d291974 --- /dev/null +++ b/python/testData/refactoring/rename/renameReassignedParameter_after.py @@ -0,0 +1,6 @@ +def cover(a, bar=1): + item = a + bar + bar = 1 + if a > 1: + bar = cover(item, bar) + return bar \ No newline at end of file diff --git a/python/testData/refactoring/rename/renameShadowingVariable.py b/python/testData/refactoring/rename/renameShadowingVariable.py new file mode 100644 index 000000000000..bc7946d9ec3c --- /dev/null +++ b/python/testData/refactoring/rename/renameShadowingVariable.py @@ -0,0 +1,3 @@ +def lab(): pass +lab = 1 +print(lab) diff --git a/python/testData/refactoring/rename/renameShadowingVariable_after.py b/python/testData/refactoring/rename/renameShadowingVariable_after.py new file mode 100644 index 000000000000..1f26476ab745 --- /dev/null +++ b/python/testData/refactoring/rename/renameShadowingVariable_after.py @@ -0,0 +1,3 @@ +def lab(): pass +bar = 1 +print(bar) diff --git a/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java b/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java index 3dad95b96527..956b7867b150 100644 --- a/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java +++ b/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java @@ -1,7 +1,11 @@ package com.jetbrains.python; +import com.intellij.codeInsight.TargetElementUtilBase; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; import com.intellij.usageView.UsageInfo; import com.jetbrains.python.fixtures.PyTestCase; +import com.jetbrains.python.psi.LanguageLevel; import java.util.*; @@ -111,4 +115,26 @@ public class PyFindUsagesTest extends PyTestCase { "testMethod = staticmethod(testMethod)", "testMethod = staticmethod(testMethod)"); } + + // PY-7348 + public void testNamespacePackageUsages() { + setLanguageLevel(LanguageLevel.PYTHON33); + try { + final Collection usages = findMultiFileUsages("a.py"); + assertEquals(3, usages.size()); + } finally { + setLanguageLevel(null); + } + } + + private Collection findMultiFileUsages(String filename) { + final String testName = getTestName(false); + myFixture.copyDirectoryToProject("findUsages/" + testName, ""); + PsiDocumentManager.getInstance(myFixture.getProject()).commitAllDocuments(); + myFixture.configureFromTempProjectFile(filename); + final int flags = TargetElementUtilBase.ELEMENT_NAME_ACCEPTED | TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED; + final PsiElement element = TargetElementUtilBase.findTargetElement(myFixture.getEditor(), flags); + assertNotNull(element); + return myFixture.findUsages(element); + } } diff --git a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java index 68440e23bb0e..d55cf9c6a58b 100644 --- a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java +++ b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java @@ -9,7 +9,6 @@ import com.jetbrains.cython.psi.CythonFunction; import com.jetbrains.cython.psi.CythonVariable; import com.jetbrains.python.fixtures.PyResolveTestCase; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.impl.PyImportedModule; /** * @author yole @@ -364,10 +363,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase { // PY-2813 public void testNamespacePackage() { - final PsiElement element = doResolve(); - assertInstanceOf(element, PyImportedModule.class); - final PyImportedModule module = (PyImportedModule)element; - assertEquals("p1", module.getImportedPrefix().toString()); + assertResolvesTo(PsiDirectory.class, "p1"); } // PY-2813 @@ -408,10 +404,7 @@ public class PyMultiFileResolveTest extends PyResolveTestCase { public void testPython33NamespacePackage() { setLanguageLevel(LanguageLevel.PYTHON33); try { - final PsiElement element = doResolve(); - assertInstanceOf(element, PyImportedModule.class); - final PyImportedModule module = (PyImportedModule)element; - assertEquals("p1", module.getImportedPrefix().toString()); + assertResolvesTo(PsiDirectory.class, "p1"); } finally { setLanguageLevel(null); } diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java index c2c0c3442a11..d19648feefbf 100644 --- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java @@ -591,9 +591,13 @@ public class PythonCompletionTest extends PyTestCase { doTest(); } + public void testDunderClass() { // PY-7327 + doTest(); + } + public void testAsInWith() { // PY-3701 setLanguageLevel(LanguageLevel.PYTHON27); - assertTrue(doTestByText("with foo ").contains("as")); + assertTrue(doTestByText("with open(foo) ").contains("as")); } public void testAsInExcept() { // PY-1846 diff --git a/python/testSrc/com/jetbrains/python/codeInsight/PyCompletionPatternsTest.java b/python/testSrc/com/jetbrains/python/codeInsight/PyCompletionPatternsTest.java index 1e8b95982010..539f6451c727 100644 --- a/python/testSrc/com/jetbrains/python/codeInsight/PyCompletionPatternsTest.java +++ b/python/testSrc/com/jetbrains/python/codeInsight/PyCompletionPatternsTest.java @@ -1,25 +1,33 @@ package com.jetbrains.python.codeInsight; +import com.intellij.patterns.ElementPattern; import com.intellij.psi.PsiElement; import com.jetbrains.python.PythonFileType; import com.jetbrains.python.codeInsight.completion.PyKeywordCompletionContributor; import com.jetbrains.python.fixtures.PyTestCase; +import com.jetbrains.python.psi.LanguageLevel; /** * @author yole */ public class PyCompletionPatternsTest extends PyTestCase { public void testInFromImportAfterRef() { - String text = "from . im"; - myFixture.configureByText(PythonFileType.INSTANCE, text); - PsiElement element = myFixture.getFile().findElementAt(text.length() - 1); - assertTrue(PyKeywordCompletionContributor.IN_FROM_IMPORT_AFTER_REF.accepts(element)); + assertTrue(doTest("from . im", PyKeywordCompletionContributor.IN_FROM_IMPORT_AFTER_REF)); } public void testAfterQualifier() { - String text = "from . im"; + assertFalse(doTest("from . im", PyKeywordCompletionContributor.AFTER_QUALIFIER)); + } + + public void testWith() { + setLanguageLevel(LanguageLevel.PYTHON27); + assertTrue(doTest("with open(foo) ", PyKeywordCompletionContributor.IN_WITH_AFTER_REF)); + assertFalse(doTest("with open(foo) as ", PyKeywordCompletionContributor.IN_WITH_AFTER_REF)); + } + + private boolean doTest(final String text, final ElementPattern ref) { myFixture.configureByText(PythonFileType.INSTANCE, text); PsiElement element = myFixture.getFile().findElementAt(text.length() - 1); - assertFalse(PyKeywordCompletionContributor.AFTER_QUALIFIER.accepts(element)); + return ref.accepts(element); } } diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 49d530b3777f..a5bbed89e7b9 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -185,6 +185,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase { doTest(); } + // PY-7315 + public void testImportUsedInDocString() { + doTest(); + } + private void doTest() { myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py"); myFixture.enableInspections(PyUnresolvedReferencesInspection.class); diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java index 58cf712cfcec..ca5e06eb7be7 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java @@ -91,6 +91,14 @@ public class PyRenameTest extends PyTestCase { doTest("bar"); } + public void testRenameReassignedParameter() { // PY-3698 + doTest("bar"); + } + + public void testRenameShadowingVariable() { // PY-7342 + doTest("bar"); + } + public void testRenameProperty() { // PY-5948 setLanguageLevel(LanguageLevel.PYTHON26); try {