diff --git a/python/openapi/src/com/jetbrains/python/psi/RootFileReferenceSet.java b/python/openapi/src/com/jetbrains/python/psi/RootFileReferenceSet.java
index 62458697c662..b87484cf7be0 100644
--- a/python/openapi/src/com/jetbrains/python/psi/RootFileReferenceSet.java
+++ b/python/openapi/src/com/jetbrains/python/psi/RootFileReferenceSet.java
@@ -35,7 +35,12 @@ public class RootFileReferenceSet extends FileReferenceSet {
}
public boolean isAbsolutePathReference() {
- return FileUtil.isAbsolute(getPathString());
+ if (!ApplicationManager.getApplication().isUnitTestMode()) {
+ return FileUtil.isAbsolute(getPathString());
+ }
+ else {
+ return super.isAbsolutePathReference();
+ }
}
@NotNull
diff --git a/python/python-rest/resources/META-INF/python-rest-plugin.xml b/python/python-rest/resources/META-INF/python-rest-plugin.xml
index 9079ba287038..82560a244d7f 100644
--- a/python/python-rest/resources/META-INF/python-rest-plugin.xml
+++ b/python/python-rest/resources/META-INF/python-rest-plugin.xml
@@ -15,6 +15,7 @@
+
diff --git a/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java b/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
index f7834e3a826a..af8696d1b11a 100644
--- a/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
+++ b/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
@@ -8,11 +8,13 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.SystemInfo;
import com.jetbrains.python.packaging.PyExternalProcessException;
import com.jetbrains.python.packaging.PyPackage;
import com.jetbrains.python.packaging.PyPackageManager;
import com.jetbrains.python.packaging.PyPackageManagerImpl;
import com.jetbrains.python.sdk.PythonSdkType;
+import org.jetbrains.annotations.Nullable;
/**
* User : catherine
@@ -36,7 +38,7 @@ public class RestPythonUtil {
PyPackageManagerImpl manager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
try {
final PyPackage sphinx = manager.findPackage("Sphinx");
- String quickStart = RestUtil.findQuickStart(sdk.getHomePath());
+ String quickStart = findQuickStart(sdk);
presentation.setEnabled(sphinx != null && quickStart != null);
}
catch (PyExternalProcessException ignored) {
@@ -47,4 +49,9 @@ public class RestPythonUtil {
return presentation;
}
+ @Nullable
+ public static String findQuickStart(final Sdk sdkHome) {
+ final String runnerName = "sphinx-quickstart" + (SystemInfo.isWindows ? ".exe" : "");
+ return PythonSdkType.getExecutablePath(sdkHome, runnerName);
+ }
}
diff --git a/python/python-rest/src/com/jetbrains/rest/completion/SphinxDirectiveCompletionContributor.java b/python/python-rest/src/com/jetbrains/rest/completion/SphinxDirectiveCompletionContributor.java
new file mode 100644
index 000000000000..8ab112dde9a0
--- /dev/null
+++ b/python/python-rest/src/com/jetbrains/rest/completion/SphinxDirectiveCompletionContributor.java
@@ -0,0 +1,47 @@
+package com.jetbrains.rest.completion;
+
+import com.intellij.codeInsight.completion.*;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.patterns.PsiElementPattern;
+import com.intellij.psi.PsiElement;
+import com.intellij.util.ProcessingContext;
+import com.jetbrains.rest.RestPythonUtil;
+import com.jetbrains.rest.RestTokenTypes;
+import com.jetbrains.rest.RestUtil;
+import com.jetbrains.rest.psi.RestReferenceTarget;
+import org.jetbrains.annotations.NotNull;
+
+import static com.intellij.patterns.PlatformPatterns.psiElement;
+import static com.intellij.patterns.StandardPatterns.or;
+
+/**
+ * User : ktisha
+ */
+public class SphinxDirectiveCompletionContributor extends CompletionContributor {
+ public static final PsiElementPattern.Capture DIRECTIVE_PATTERN = psiElement().afterSibling(or(psiElement().
+ withElementType(RestTokenTypes.WHITESPACE).afterSibling(psiElement(RestReferenceTarget.class)),
+ psiElement().withElementType(RestTokenTypes.EXPLISIT_MARKUP_START)));
+
+ public SphinxDirectiveCompletionContributor() {
+ extend(CompletionType.BASIC, DIRECTIVE_PATTERN,
+ new CompletionProvider() {
+ @Override
+ protected void addCompletions(@NotNull CompletionParameters parameters,
+ ProcessingContext context,
+ @NotNull CompletionResultSet result) {
+ Sdk sdk = ProjectRootManager.getInstance(parameters.getPosition().getProject()).getProjectSdk();
+ if (sdk != null) {
+ String sphinx = RestPythonUtil.findQuickStart(sdk);
+ if (sphinx != null) {
+ for (String tag : RestUtil.SPHINX_DIRECTIVES) {
+ result.addElement(LookupElementBuilder.create(tag));
+ }
+ }
+ }
+ }
+ }
+ );
+ }
+}
diff --git a/python/python-rest/src/com/jetbrains/rest/inspections/RestRoleInspection.java b/python/python-rest/src/com/jetbrains/rest/inspections/RestRoleInspection.java
index f7c89927a729..1663aa9cb2ad 100644
--- a/python/python-rest/src/com/jetbrains/rest/inspections/RestRoleInspection.java
+++ b/python/python-rest/src/com/jetbrains/rest/inspections/RestRoleInspection.java
@@ -19,10 +19,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.HashSet;
import com.jetbrains.python.ReSTService;
import com.jetbrains.python.psi.*;
-import com.jetbrains.rest.RestBundle;
-import com.jetbrains.rest.RestFile;
-import com.jetbrains.rest.RestTokenTypes;
-import com.jetbrains.rest.RestUtil;
+import com.jetbrains.rest.*;
import com.jetbrains.rest.psi.RestDirectiveBlock;
import com.jetbrains.rest.psi.RestRole;
import com.jetbrains.rest.quickfixes.AddIgnoredRoleFix;
@@ -114,7 +111,7 @@ public class RestRoleInspection extends RestInspection {
Sdk sdk = ProjectRootManager.getInstance(node.getProject()).getProjectSdk();
if (sdk != null) {
- String sphinx = RestUtil.findQuickStart(sdk.getHomePath());
+ String sphinx = RestPythonUtil.findQuickStart(sdk);
if (sphinx != null) {
if (RestUtil.SPHINX_ROLES.contains(node.getText()) || RestUtil.SPHINX_ROLES.contains(":py"+node.getText())
|| mySphinxRoles.contains(node.getRoleName())) return;
diff --git a/python/python-rest/src/com/jetbrains/rest/sphinx/SphinxBaseCommand.java b/python/python-rest/src/com/jetbrains/rest/sphinx/SphinxBaseCommand.java
index 7e0d79089cd3..1ef90a635916 100644
--- a/python/python-rest/src/com/jetbrains/rest/sphinx/SphinxBaseCommand.java
+++ b/python/python-rest/src/com/jetbrains/rest/sphinx/SphinxBaseCommand.java
@@ -22,7 +22,7 @@ import com.jetbrains.python.run.PythonCommandLineState;
import com.jetbrains.python.run.PythonProcessRunner;
import com.jetbrains.python.run.PythonTracebackFilter;
import com.jetbrains.python.sdk.PythonSdkType;
-import com.jetbrains.rest.RestUtil;
+import com.jetbrains.rest.RestPythonUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -169,6 +169,6 @@ public class SphinxBaseCommand {
@Nullable
private static String getCommandPath(Sdk sdk) {
- return RestUtil.findQuickStart(sdk.getHomePath());
+ return RestPythonUtil.findQuickStart(sdk);
}
}
diff --git a/python/resources/inspectionDescriptions/PyShadowingBuiltinsInspection.html b/python/resources/inspectionDescriptions/PyShadowingBuiltinsInspection.html
new file mode 100644
index 000000000000..f25c27847c4f
--- /dev/null
+++ b/python/resources/inspectionDescriptions/PyShadowingBuiltinsInspection.html
@@ -0,0 +1,5 @@
+
+
+This inspection detects shadowing built-in names, such as 'len' or 'list'.
+
+
\ No newline at end of file
diff --git a/python/resources/inspectionDescriptions/PyShadowingNamesInspection.html b/python/resources/inspectionDescriptions/PyShadowingNamesInspection.html
index 3f32f07ca884..dabfaf0b94a1 100644
--- a/python/resources/inspectionDescriptions/PyShadowingNamesInspection.html
+++ b/python/resources/inspectionDescriptions/PyShadowingNamesInspection.html
@@ -1,5 +1,5 @@
-This inspection detects shadowing names defined in outer scopes, including built-in names.
+This inspection detects shadowing names defined in outer scopes.
\ No newline at end of file
diff --git a/python/rest/src/com/jetbrains/rest/RestUtil.java b/python/rest/src/com/jetbrains/rest/RestUtil.java
index 1ef5b1a8511b..7a177693112f 100644
--- a/python/rest/src/com/jetbrains/rest/RestUtil.java
+++ b/python/rest/src/com/jetbrains/rest/RestUtil.java
@@ -2,11 +2,7 @@ package com.jetbrains.rest;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import com.intellij.openapi.util.SystemInfo;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import org.jetbrains.annotations.Nullable;
-import java.io.File;
import java.util.Map;
import java.util.Set;
@@ -16,32 +12,6 @@ import java.util.Set;
public class RestUtil {
private RestUtil() {}
- @Nullable
- public static String findQuickStart(final String sdkHome) {
- final String runnerName = "sphinx-quickstart" + (SystemInfo.isWindows ? ".exe" : "");
- File binPath = new File(sdkHome);
- File binDir = binPath.getParentFile();
- if (binDir == null) return null;
- File runner = new File(binDir, runnerName);
- if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
- runner = new File(new File(binDir, "scripts"), runnerName);
- if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
- runner = new File(new File(binDir.getParentFile(), "scripts"), runnerName);
- if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
- runner = new File(new File(binDir.getParentFile(), "local"), runnerName);
- if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
- runner = new File(new File (new File(binDir.getParentFile(), "local"), "bin"), runnerName);
- if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
-
- // Search in standard unix path
- runner = new File(new File("/usr", "bin"), runnerName);
- if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
- runner = new File(new File (new File("/usr", "local"), "bin"), runnerName);
- if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
-
- return null;
- }
-
public static String[] SPHINX_DIRECTIVES = new String[] {
"module::" , "automodule::" , "autoclass::" , "toctree::" , "glossary::" , "code-block::", "versionadded::",
"versionchanged::", "deprecated::", "seealso::", "centered::", "hlist::", "index::", "productionlist::", "highlight::",
diff --git a/python/rest/src/com/jetbrains/rest/completion/DirectiveCompletionContributor.java b/python/rest/src/com/jetbrains/rest/completion/DirectiveCompletionContributor.java
index 97df88310566..22e127cc0659 100644
--- a/python/rest/src/com/jetbrains/rest/completion/DirectiveCompletionContributor.java
+++ b/python/rest/src/com/jetbrains/rest/completion/DirectiveCompletionContributor.java
@@ -2,8 +2,6 @@ package com.jetbrains.rest.completion;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.patterns.PsiElementPattern;
import com.intellij.psi.PsiElement;
import com.intellij.util.ProcessingContext;
@@ -33,15 +31,6 @@ public class DirectiveCompletionContributor extends CompletionContributor {
for (String tag : RestUtil.getDirectives()) {
result.addElement(LookupElementBuilder.create(tag));
}
- Sdk sdk = ProjectRootManager.getInstance(parameters.getPosition().getProject()).getProjectSdk();
- if (sdk != null) {
- String sphinx = RestUtil.findQuickStart(sdk.getHomePath());
- if (sphinx != null) {
- for (String tag : RestUtil.SPHINX_DIRECTIVES) {
- result.addElement(LookupElementBuilder.create(tag));
- }
- }
- }
}
}
);
diff --git a/python/src/META-INF/python-plugin-core.xml b/python/src/META-INF/python-plugin-core.xml
index 12f60d8d6362..8858ffbac17e 100644
--- a/python/src/META-INF/python-plugin-core.xml
+++ b/python/src/META-INF/python-plugin-core.xml
@@ -323,7 +323,8 @@
-
+
+
diff --git a/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java b/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java
index 6b1268c12e48..007ee734bf61 100644
--- a/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java
@@ -74,8 +74,7 @@ public class PyRedeclarationInspection extends PyInspection {
}
private static boolean isConditional(@NotNull PsiElement node) {
- return PsiTreeUtil.getParentOfType(node, PyIfStatement.class, PyConditionalExpression.class, PyLoopStatement.class,
- PyComprehensionElement.class, PyTryExceptStatement.class) != null;
+ return PsiTreeUtil.getParentOfType(node, PyIfStatement.class, PyConditionalExpression.class, PyTryExceptStatement.class) != null;
}
private static boolean isDecorated(@NotNull PyDecoratable node) {
@@ -118,17 +117,20 @@ public class PyRedeclarationInspection extends PyInspection {
if (rwInstruction.getAccess().isWriteAccess()) {
final List quickFixes = new ArrayList();
final PsiElement originalElement = rwInstruction.getElement();
- if (originalElement != null && suggestRename(element, originalElement)) {
- quickFixes.add(new PyRenameElementQuickFix());
+ if (originalElement != null && originalElement != element) {
+ if (suggestRename(element, originalElement)) {
+ quickFixes.add(new PyRenameElementQuickFix());
+ }
+ final PsiElement identifier = element.getNameIdentifier();
+ registerProblem(identifier != null ? identifier : element,
+ PyBundle.message("INSP.redeclared.name", name),
+ ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
+ null,
+ quickFixes.toArray(new LocalQuickFix[quickFixes.size()]));
+ return ControlFlowUtil.Operation.BREAK;
}
- final PsiElement identifier = element.getNameIdentifier();
- registerProblem(identifier != null ? identifier : element,
- PyBundle.message("INSP.redeclared.name", name),
- ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
- null,
- quickFixes.toArray(new LocalQuickFix[quickFixes.size()]));
}
- return ControlFlowUtil.Operation.BREAK;
+ return ControlFlowUtil.Operation.CONTINUE;
}
}
return ControlFlowUtil.Operation.NEXT;
diff --git a/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java
new file mode 100644
index 000000000000..94b06b54e474
--- /dev/null
+++ b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java
@@ -0,0 +1,144 @@
+package com.jetbrains.python.inspections;
+
+import com.google.common.collect.ImmutableSet;
+import com.intellij.codeInsight.intention.LowPriorityAction;
+import com.intellij.codeInspection.*;
+import com.intellij.codeInspection.ui.ListEditForm;
+import com.intellij.openapi.project.Project;
+import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.PsiNameIdentifierOwner;
+import com.intellij.util.Consumer;
+import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
+import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.impl.PyBuiltinCache;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Warns about shadowing built-in names.
+ *
+ * @author vlan
+ */
+public class PyShadowingBuiltinsInspection extends PyInspection {
+ // Persistent settings
+ public List ignoredNames = new ArrayList();
+
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return "Shadowing built-ins";
+ }
+
+ @Override
+ public JComponent createOptionsPanel() {
+ final ListEditForm form = new ListEditForm("Ignore built-ins", ignoredNames);
+ return form.getContentPanel();
+ }
+
+ @NotNull
+ @Override
+ public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
+ boolean isOnTheFly,
+ @NotNull LocalInspectionToolSession session) {
+ return new Visitor(holder, session, ignoredNames);
+ }
+
+ private static class Visitor extends PyInspectionVisitor {
+ private final Set myIgnoredNames;
+
+ public Visitor(@Nullable ProblemsHolder holder, @NotNull LocalInspectionToolSession session, @NotNull Collection ignoredNames) {
+ super(holder, session);
+ myIgnoredNames = ImmutableSet.copyOf(ignoredNames);
+ }
+
+ @Override
+ public void visitPyClass(@NotNull PyClass node) {
+ processElement(node);
+ }
+
+ @Override
+ public void visitPyFunction(@NotNull PyFunction node) {
+ processElement(node);
+ }
+
+ @Override
+ public void visitPyNamedParameter(@NotNull PyNamedParameter node) {
+ processElement(node);
+ }
+
+ @Override
+ public void visitPyTargetExpression(@NotNull PyTargetExpression node) {
+ if (node.getQualifier() == null) {
+ processElement(node);
+ }
+ }
+
+ private void processElement(@NotNull PsiNameIdentifierOwner element) {
+ final ScopeOwner owner = ScopeUtil.getScopeOwner(element);
+ if (owner instanceof PyClass) {
+ return;
+ }
+ final String name = element.getName();
+ if (name != null && !myIgnoredNames.contains(name)) {
+ final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(element);
+ final PsiElement builtin = builtinCache.getByName(name);
+ if (builtin != null && !PyUtil.inSameFile(builtin, element)) {
+ final PsiElement identifier = element.getNameIdentifier();
+ final PsiElement problemElement = identifier != null ? identifier : element;
+ registerProblem(problemElement, String.format("Shadows built-in name '%s'", name),
+ ProblemHighlightType.WEAK_WARNING, null, new PyRenameElementQuickFix(), new PyIgnoreBuiltinQuickFix(name));
+ }
+ }
+ }
+
+ private static class PyIgnoreBuiltinQuickFix implements LocalQuickFix, LowPriorityAction {
+ @NotNull private final String myName;
+
+ private PyIgnoreBuiltinQuickFix(@NotNull String name) {
+ myName = name;
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return getFamilyName() + " \"" + myName + "\"";
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return "Ignore shadowed built-in name";
+ }
+
+ @Override
+ public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
+ final PsiElement element = descriptor.getPsiElement();
+ if (element != null) {
+ final InspectionProfile profile = InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
+ profile.modifyProfile(new Consumer() {
+ @Override
+ public void consume(ModifiableModel model) {
+ final String toolName = PyShadowingBuiltinsInspection.class.getSimpleName();
+ final PyShadowingBuiltinsInspection inspection = (PyShadowingBuiltinsInspection)model.getUnwrappedTool(toolName, element);
+ if (inspection != null) {
+ if (!inspection.ignoredNames.contains(myName)) {
+ inspection.ignoredNames.add(myName);
+ }
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+}
+
diff --git a/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java b/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java
index c19945da06df..aad248db7c95 100644
--- a/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java
@@ -1,52 +1,32 @@
package com.jetbrains.python.inspections;
-import com.google.common.collect.ImmutableSet;
-import com.intellij.codeInsight.intention.LowPriorityAction;
-import com.intellij.codeInspection.*;
-import com.intellij.codeInspection.ui.ListEditForm;
-import com.intellij.openapi.project.Project;
-import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
+import com.intellij.codeInspection.LocalInspectionToolSession;
+import com.intellij.codeInspection.ProblemHighlightType;
+import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiNameIdentifierOwner;
import com.intellij.psi.util.PsiTreeUtil;
-import com.intellij.util.Consumer;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
-import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.resolve.PyResolveUtil;
import com.jetbrains.python.psi.resolve.ResolveProcessor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.*;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
/**
* Warns about shadowing names defined in outer scopes.
*
* @author vlan
*/
public class PyShadowingNamesInspection extends PyInspection {
- // Persistent settings
- public List ignoredNames = new ArrayList();
-
@NotNull
@Override
public String getDisplayName() {
- return "Shadowing names";
- }
-
- @Override
- public JComponent createOptionsPanel() {
- final ListEditForm form = new ListEditForm("Ignore built-ins", ignoredNames);
- return form.getContentPanel();
+ return "Shadowing names from outer scopes";
}
@NotNull
@@ -54,15 +34,12 @@ public class PyShadowingNamesInspection extends PyInspection {
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
boolean isOnTheFly,
@NotNull LocalInspectionToolSession session) {
- return new Visitor(holder, session, ignoredNames);
+ return new Visitor(holder, session);
}
private static class Visitor extends PyInspectionVisitor {
- private final Set myIgnoredNames;
-
- public Visitor(@Nullable ProblemsHolder holder, @NotNull LocalInspectionToolSession session, @NotNull Collection ignoredNames) {
+ public Visitor(@Nullable ProblemsHolder holder, @NotNull LocalInspectionToolSession session) {
super(holder, session);
- myIgnoredNames = ImmutableSet.copyOf(ignoredNames);
}
@Override
@@ -92,99 +69,35 @@ public class PyShadowingNamesInspection extends PyInspection {
private void processElement(@NotNull PsiNameIdentifierOwner element) {
final ScopeOwner owner = ScopeUtil.getScopeOwner(element);
- // Class-level names are rarely accessed inside at the class level, usually they are accessed as attributes
if (owner instanceof PyClass) {
return;
}
final String name = element.getName();
- if (name != null && !myIgnoredNames.contains(name)) {
+ if (name != null) {
final PsiElement identifier = element.getNameIdentifier();
final PsiElement problemElement = identifier != null ? identifier : element;
- final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(element);
- final PsiElement builtin = builtinCache.getByName(name);
- if (builtin != null) {
- processBuiltin(element, name, problemElement, builtin);
+ if ("_".equals(name)) {
+ return;
}
- else {
- processOuterScope(element, name, problemElement);
- }
- }
- }
-
- private void processBuiltin(@NotNull PsiNameIdentifierOwner element,
- @NotNull String name,
- @NotNull PsiElement problemElement,
- @NotNull PsiElement builtin) {
- if (!PyUtil.inSameFile(builtin, element)) {
- registerProblem(problemElement, String.format("Shadows built-in name '%s'", name),
- ProblemHighlightType.WEAK_WARNING, null, new PyRenameElementQuickFix(),
- new PyIgnoreBuiltinQuickFix(name));
- }
- }
-
- private void processOuterScope(@NotNull PsiNameIdentifierOwner element, @NotNull String name, @NotNull PsiElement problemElement) {
- if ("_".equals(name)) {
- return;
- }
- final ScopeOwner owner = ScopeUtil.getScopeOwner(element);
- if (owner != null) {
- final ScopeOwner nextOwner = ScopeUtil.getScopeOwner(owner);
- if (nextOwner != null) {
- final ResolveProcessor processor = new ResolveProcessor(name);
- PyResolveUtil.scopeCrawlUp(processor, nextOwner, null, name, null);
- final PsiElement resolved = processor.getResult();
- if (resolved != null) {
- final PyComprehensionElement comprehension = PsiTreeUtil.getParentOfType(resolved, PyComprehensionElement.class);
- if (comprehension != null && PyUtil.isOwnScopeComprehension(comprehension)) {
- return;
- }
- final Scope scope = ControlFlowCache.getScope(owner);
- if (scope.isGlobal(name) || scope.isNonlocal(name)) {
- return;
- }
- registerProblem(problemElement, String.format("Shadows name '%s' from outer scope", name),
- ProblemHighlightType.WEAK_WARNING, null, new PyRenameElementQuickFix());
- }
- }
- }
- }
-
- private static class PyIgnoreBuiltinQuickFix implements LocalQuickFix, LowPriorityAction {
- @NotNull private final String myName;
-
- private PyIgnoreBuiltinQuickFix(@NotNull String name) {
- myName = name;
- }
-
- @NotNull
- @Override
- public String getName() {
- return getFamilyName() + " \"" + myName + "\"";
- }
-
- @NotNull
- @Override
- public String getFamilyName() {
- return "Ignore shadowed built-in name";
- }
-
- @Override
- public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
- final PsiElement element = descriptor.getPsiElement();
- if (element != null) {
- final InspectionProfile profile = InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
- profile.modifyProfile(new Consumer() {
- @Override
- public void consume(ModifiableModel model) {
- final String toolName = PyShadowingNamesInspection.class.getSimpleName();
- final PyShadowingNamesInspection inspection = (PyShadowingNamesInspection)model.getUnwrappedTool(toolName, element);
- if (inspection != null) {
- if (!inspection.ignoredNames.contains(myName)) {
- inspection.ignoredNames.add(myName);
- }
+ if (owner != null) {
+ final ScopeOwner nextOwner = ScopeUtil.getScopeOwner(owner);
+ if (nextOwner != null) {
+ final ResolveProcessor processor = new ResolveProcessor(name);
+ PyResolveUtil.scopeCrawlUp(processor, nextOwner, null, name, null);
+ final PsiElement resolved = processor.getResult();
+ if (resolved != null) {
+ final PyComprehensionElement comprehension = PsiTreeUtil.getParentOfType(resolved, PyComprehensionElement.class);
+ if (comprehension != null && PyUtil.isOwnScopeComprehension(comprehension)) {
+ return;
}
+ final Scope scope = ControlFlowCache.getScope(owner);
+ if (scope.isGlobal(name) || scope.isNonlocal(name)) {
+ return;
+ }
+ registerProblem(problemElement, String.format("Shadows name '%s' from outer scope", name),
+ ProblemHighlightType.WEAK_WARNING, null, new PyRenameElementQuickFix());
}
- });
+ }
}
}
}
diff --git a/python/src/com/jetbrains/python/run/PythonCommandLineState.java b/python/src/com/jetbrains/python/run/PythonCommandLineState.java
index 55cb57bedc34..b82b3d6c6eb1 100644
--- a/python/src/com/jetbrains/python/run/PythonCommandLineState.java
+++ b/python/src/com/jetbrains/python/run/PythonCommandLineState.java
@@ -299,8 +299,12 @@ public abstract class PythonCommandLineState extends CommandLineState {
}
private static void addIfNeeded(@NotNull final VirtualFile file, @NotNull final Collection pathList) {
+ addIfNeeded(pathList, file.getPath());
+ }
+
+ protected static void addIfNeeded(Collection pathList, String path) {
final Set vals = Sets.newHashSet(pathList);
- final String filePath = FileUtil.toSystemDependentName(file.getPath());
+ final String filePath = FileUtil.toSystemDependentName(path);
if (!vals.contains(filePath)) {
pathList.add(filePath);
}
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
index 8f266af4d084..543f251c0723 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
@@ -867,6 +867,37 @@ public class PythonSdkType extends SdkType {
return null;
}
+ @Nullable
+ public static String getExecutablePath(@NotNull final String homeDirectory, @NotNull String name) {
+ File binPath = new File(homeDirectory);
+ File binDir = binPath.getParentFile();
+ if (binDir == null) return null;
+ File runner = new File(binDir, name);
+ if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
+ runner = new File(new File(binDir, "Scripts"), name);
+ if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
+ runner = new File(new File(binDir.getParentFile(), "Scripts"), name);
+ if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
+ runner = new File(new File(binDir.getParentFile(), "local"), name);
+ if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
+ runner = new File(new File(new File(binDir.getParentFile(), "local"), "bin"), name);
+ if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
+
+ // Search in standard unix path
+ runner = new File(new File("/usr", "bin"), name);
+ if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
+ runner = new File(new File (new File("/usr", "local"), "bin"), name);
+ if (runner.exists()) return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath());
+ return null;
+ }
+
+ @Nullable
+ public static String getExecutablePath(@NotNull final Sdk sdk, @NotNull String name) {
+ final String homeDirectory = sdk.getHomePath();
+ if (homeDirectory == null) return null;
+ return getExecutablePath(homeDirectory, name);
+ }
+
private static String[] getBinaryNames() {
if (SystemInfo.isUnix) {
return UNIX_BINARY_NAMES;
diff --git a/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java b/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java
index 11a55713bbbe..1fcf5b4cd8cd 100644
--- a/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java
+++ b/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java
@@ -4,6 +4,7 @@ import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.configurations.ParamsGroup;
import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration;
@@ -37,15 +38,16 @@ public class PythonUnitTestCommandLineState extends
protected List getTestSpecs() {
List specs = new ArrayList();
+ final String scriptName = FileUtil.toSystemDependentName(myConfig.getScriptName());
switch (myConfig.getTestType()) {
case TEST_SCRIPT:
- specs.add(myConfig.getScriptName());
+ specs.add(scriptName);
break;
case TEST_CLASS:
- specs.add(myConfig.getScriptName() + "::" + myConfig.getClassName());
+ specs.add(scriptName + "::" + myConfig.getClassName());
break;
case TEST_METHOD:
- specs.add(myConfig.getScriptName() + "::" + myConfig.getClassName() + "::" + myConfig.getMethodName());
+ specs.add(scriptName + "::" + myConfig.getClassName() + "::" + myConfig.getMethodName());
break;
case TEST_FOLDER:
if (!StringUtil.isEmpty(myConfig.getPattern()) && myConfig.usePattern()) {
@@ -56,7 +58,7 @@ public class PythonUnitTestCommandLineState extends
}
break;
case TEST_FUNCTION:
- specs.add(myConfig.getScriptName() + "::::" + myConfig.getMethodName());
+ specs.add(scriptName + "::::" + myConfig.getMethodName());
break;
default:
throw new IllegalArgumentException("Unknown test type: " + myConfig.getTestType());
diff --git a/python/testData/inspections/PyRedeclarationInspection/test.py b/python/testData/inspections/PyRedeclarationInspection/test.py
index 58a1f1541abf..a8895dade5f5 100644
--- a/python/testData/inspections/PyRedeclarationInspection/test.py
+++ b/python/testData/inspections/PyRedeclarationInspection/test.py
@@ -43,7 +43,7 @@ def test_local_variable():
x = 2
-def conditional(c):
+def test_conditional(c):
def foo():
pass
@@ -51,12 +51,39 @@ def conditional(c):
def foo():
pass
- while c:
- def foo():
- pass
-
try:
def foo():
pass
except:
pass
+
+
+def test_while_loop(c):
+ def foo():
+ pass
+
+ while c:
+ def foo():
+ pass
+
+
+class TestForLoopNoRedeclaraion:
+ for foo in [1, 2, 3]:
+ x = 1
+
+
+class TestForLoopTarget:
+ def foo():
+ pass
+
+ for foo in [1, 2, 3]:
+ x = 1
+
+
+class TestForLoopBody:
+ def foo():
+ pass
+
+ for _ in [1, 2, 3]:
+ def foo():
+ pass
diff --git a/python/testData/inspections/PyShadowingBuiltinsInspection/test.py b/python/testData/inspections/PyShadowingBuiltinsInspection/test.py
new file mode 100644
index 000000000000..4951bf1fdf50
--- /dev/null
+++ b/python/testData/inspections/PyShadowingBuiltinsInspection/test.py
@@ -0,0 +1,50 @@
+def test_import_builtin_names():
+ import float
+ from foo import float
+ from bar import baz as float
+
+
+def test_builtin_function_parameters():
+ def test1(x, _, len, file=None):
+ pass
+
+
+def test_builtin_function_name():
+ def list():
+ pass
+
+
+def test_builtin_assignment_targets():
+ foo = 2
+ list = []
+ for int in range(10):
+ print(int)
+ range = []
+ list, _ = (1, 2)
+ return [int for int in range(10)]
+
+
+def test_builtin_class_name():
+ class list(object):
+ pass
+
+
+def test_builtin_method_name():
+ class C:
+ def list(self):
+ pass
+
+
+# PY-8646
+def test_builtin_qualified_name():
+ test1.range = float()
+
+ class C:
+ def foo(self):
+ self.list = []
+
+
+# PY-10164
+def test_builtin_class_attribute():
+ class C:
+ id = 1
diff --git a/python/testData/inspections/PyShadowingNamesInspection/test.py b/python/testData/inspections/PyShadowingNamesInspection/test.py
index 98eec4846722..b87b8b27bae3 100644
--- a/python/testData/inspections/PyShadowingNamesInspection/test.py
+++ b/python/testData/inspections/PyShadowingNamesInspection/test.py
@@ -1,58 +1,6 @@
global_foo = 1
-def test_import_builtin_names():
- import float
- from foo import float
- from bar import baz as float
-
-
-def test_builtin_function_parameters():
- def test1(x, _, len, file=None):
- pass
-
-
-def test_builtin_function_name():
- def list():
- pass
-
-
-def test_builtin_assignment_targets():
- foo = 2
- list = []
- for int in range(10):
- print(int)
- range = []
- list, _ = (1, 2)
- return [int for int in range(10)]
-
-
-def test_builtin_class_name():
- class list(object):
- pass
-
-
-def test_builtin_method_name():
- class C:
- def list(self):
- pass
-
-
-# PY-8646
-def test_builtin_qualified_name():
- test1.range = float()
-
- class C:
- def foo(self):
- self.list = []
-
-
-# PY-10164
-def test_builtin_class_attribute():
- class C:
- id = 1
-
-
def test_outer_function():
foo = 1
def bar():
@@ -91,7 +39,7 @@ def test_outer_global():
global_foo = 2
-def test_comprehensions():
+def test_outer_comprehensions():
print(x for x in range(10))
print([y for y in range(10)])
def f(x, y):
diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
index a1b195d9b8df..f9e844134b2c 100644
--- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
+++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
@@ -433,7 +433,7 @@ public class PyQuickFixTest extends PyTestCase {
public void testRenameShadowingBuiltins() {
final String fileName = "RenameShadowingBuiltins.py";
myFixture.configureByFile(fileName);
- myFixture.enableInspections(PyShadowingNamesInspection.class);
+ myFixture.enableInspections(PyShadowingBuiltinsInspection.class);
myFixture.checkHighlighting(true, false, true);
final IntentionAction intentionAction = myFixture.getAvailableIntention("Rename element");
assertNotNull(intentionAction);
@@ -445,7 +445,7 @@ public class PyQuickFixTest extends PyTestCase {
public void testRenameFunctionShadowingBuiltins() {
final String fileName = "RenameFunctionShadowingBuiltins.py";
myFixture.configureByFile(fileName);
- myFixture.enableInspections(PyShadowingNamesInspection.class);
+ myFixture.enableInspections(PyShadowingBuiltinsInspection.class);
myFixture.checkHighlighting(true, false, true);
final IntentionAction intentionAction = myFixture.getAvailableIntention("Rename element");
assertNotNull(intentionAction);
diff --git a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java
index 183bad8ed613..06ce32a3e896 100644
--- a/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonInspectionsTest.java
@@ -295,6 +295,10 @@ public class PythonInspectionsTest extends PyTestCase {
}
// PY-5807
+ public void testPyShadowingBuiltinsInspection() {
+ doHighlightingTest(PyShadowingBuiltinsInspection.class);
+ }
+
public void testPyShadowingNamesInspection() {
doHighlightingTest(PyShadowingNamesInspection.class);
}