Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2014-11-14 16:34:15 +03:00
28 changed files with 164 additions and 85 deletions
-1
View File
@@ -79,7 +79,6 @@
<module fileurl="file://$PROJECT_DIR$/plugins/google-app-engine/google-app-engine.iml" filepath="$PROJECT_DIR$/plugins/google-app-engine/google-app-engine.iml" group="plugins/GAE" />
<module fileurl="file://$PROJECT_DIR$/plugins/google-app-engine/jps-plugin/google-app-engine-jps-plugin.iml" filepath="$PROJECT_DIR$/plugins/google-app-engine/jps-plugin/google-app-engine-jps-plugin.iml" group="plugins/GAE" />
<module fileurl="file://$PROJECT_DIR$/plugins/gradle/gradle.iml" filepath="$PROJECT_DIR$/plugins/gradle/gradle.iml" group="plugins/gradle" />
<module fileurl="file://$PROJECT_DIR$/android/tools-base/gradle-import/gradle-import.iml" filepath="$PROJECT_DIR$/android/tools-base/gradle-import/gradle-import.iml" group="android/sdktools" />
<module fileurl="file://$PROJECT_DIR$/plugins/gradle/jps-plugin/gradle-jps-plugin.iml" filepath="$PROJECT_DIR$/plugins/gradle/jps-plugin/gradle-jps-plugin.iml" group="plugins/gradle" />
<module fileurl="file://$PROJECT_DIR$/plugins/gradle/tooling-extension-api/gradle-tooling-extension-api.iml" filepath="$PROJECT_DIR$/plugins/gradle/tooling-extension-api/gradle-tooling-extension-api.iml" group="plugins/gradle" />
<module fileurl="file://$PROJECT_DIR$/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml" filepath="$PROJECT_DIR$/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml" group="plugins/gradle" />
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -44,19 +44,23 @@ public class Notification {
private Boolean myImportant;
private WeakReference<Balloon> myBalloonRef;
public Notification(@NotNull final String groupDisplayId, @NotNull final String title, @NotNull final String content, @NotNull final NotificationType type) {
public Notification(@NotNull String groupDisplayId, @NotNull String title, @NotNull String content, @NotNull NotificationType type) {
this(groupDisplayId, title, content, type, null);
}
/**
* @param groupDisplayId this should be a human-readable, capitalized string like "Facet Detector".
* It will appear in "Notifications" configurable.
* @param title notification title
* @param content notification content
* @param type notification type
* @param listener notification lifecycle listener
* @param title notification title
* @param content notification content
* @param type notification type
* @param listener notification lifecycle listener
*/
public Notification(@NotNull final String groupDisplayId, @NotNull final String title, @NotNull final String content, @NotNull final NotificationType type, @Nullable NotificationListener listener) {
public Notification(@NotNull String groupDisplayId,
@NotNull String title,
@NotNull String content,
@NotNull NotificationType type,
@Nullable NotificationListener listener) {
myGroupId = groupDisplayId;
myTitle = title;
myContent = content;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -22,12 +22,14 @@ public enum PointInImport {
NONE,
/**
* The reference is inside import and refers to a module
* The reference is inside import and it's either source qualifier in {@code from REFERENCE import ...}
* or imported name itself in {@code import REFERENCE}.
*/
AS_MODULE,
/**
* The reference is inside import and refers to a name imported from a module
* The reference is inside import and refers to a name imported from a module, i.e. it's concrete imported name in
* import statement of form {@code from somewhere import REFERENCE}, not the optional alias part.
*/
AS_NAME
}
@@ -31,7 +31,6 @@ import com.intellij.psi.util.QualifiedName;
import com.intellij.ui.components.JBList;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.CheckBox;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
@@ -39,6 +38,7 @@ import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
import com.jetbrains.python.inspections.quickfix.PyRenameElementQuickFix;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.search.PySuperMethodsSearch;
import com.jetbrains.python.psi.types.PyClassLikeType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -117,7 +117,7 @@ public class PyPep8NamingInspection extends PyInspection {
if (!LOWERCASE_REGEX.matcher(name).matches()) {
final ASTNode nameNode = function.getNameNode();
if (nameNode != null) {
final List<LocalQuickFix> quickFixes = new SmartList<LocalQuickFix>(new PyRenameElementQuickFix());
final List<LocalQuickFix> quickFixes = Lists.<LocalQuickFix>newArrayList(new PyRenameElementQuickFix());
if (containingClass != null) {
quickFixes.add(new IgnoreBaseClassQuickFix(containingClass, myTypeEvalContext));
}
@@ -135,8 +135,8 @@ public class PyPep8NamingInspection extends PyInspection {
if (blackList.contains(pyClass.getQualifiedName())) {
return true;
}
for (PyClass ancestor : pyClass.getAncestorClasses(myTypeEvalContext)) {
if (blackList.contains(ancestor.getQualifiedName())) {
for (PyClassLikeType ancestor : pyClass.getAncestorTypes(myTypeEvalContext)) {
if (blackList.contains(ancestor.getClassQName())) {
return true;
}
}
@@ -38,7 +38,6 @@ import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.text.StringUtil;
@@ -77,6 +76,7 @@ import com.jetbrains.python.refactoring.classes.PyDependenciesComparator;
import com.jetbrains.python.refactoring.classes.extractSuperclass.PyExtractSuperclassHelper;
import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -94,8 +94,6 @@ import static com.jetbrains.python.psi.PyFunction.Modifier.STATICMETHOD;
public class PyUtil {
private static final Object[] EMPTY_OBJECTS = new Object[0];
private PyUtil() {
}
@@ -992,8 +990,9 @@ public class PyUtil {
} // don't touch non-dirs
}
@Contract("null -> null; !null -> !null")
@Nullable
public static PsiElement turnInitIntoDir(PsiElement target) {
public static PsiElement turnInitIntoDir(@Nullable PsiElement target) {
if (target instanceof PyFile && isPackage((PsiFile)target)) {
return ((PsiFile)target).getContainingDirectory();
}
@@ -1230,23 +1229,6 @@ public class PyUtil {
return false;
}
public static class UnderscoreFilter implements Condition<String> {
private int myAllowed; // how many starting underscores is allowed: 0 is none, 1 is only one, 2 is two and more.
public UnderscoreFilter(int allowed) {
myAllowed = allowed;
}
public boolean value(String name) {
if (name == null) return false;
if (name.length() < 1) return false; // empty strings make no sense
int have_underscores = 0;
if (name.charAt(0) == '_') have_underscores = 1;
if (have_underscores != 0 && name.length() > 1 && name.charAt(1) == '_') have_underscores = 2;
return myAllowed >= have_underscores;
}
}
@Nullable
public static String getKeywordArgumentString(PyCallExpression expr, String keyword) {
return PyPsiUtils.strValue(expr.getKeywordArgument(keyword));
@@ -392,17 +392,16 @@ public class ResolveImportUtil {
/**
* @param element what we test (identifier, reference, import element, etc)
* @return the how the element relates to an enclosing import statement, if any
* @see com.jetbrains.python.psi.resolve.PointInImport
*/
@NotNull
public static PointInImport getPointInImport(@NotNull PsiElement element) {
PsiElement parent = PsiTreeUtil.getNonStrictParentOfType(
element,
PyImportElement.class, PyFromImportStatement.class
);
final PsiElement parent = PsiTreeUtil.getNonStrictParentOfType(element, PyImportElement.class, PyFromImportStatement.class);
if (parent instanceof PyFromImportStatement) {
return PointInImport.AS_MODULE; // from foo ...
}
if (parent instanceof PyImportElement) {
PsiElement statement = parent.getParent();
final PsiElement statement = parent.getParent();
if (statement instanceof PyImportStatement) {
return PointInImport.AS_MODULE; // import foo,...
}
@@ -15,17 +15,20 @@
*/
package com.jetbrains.python.psi.types;
import com.google.common.collect.Sets;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.QualifiedName;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.psi.AccessDirection;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.impl.PyImportedModule;
import com.jetbrains.python.psi.resolve.PointInImport;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.psi.resolve.ResolveImportUtil;
@@ -35,6 +38,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author yole
@@ -58,33 +62,37 @@ public class PyImportedModuleType implements PyType {
return new PyModuleType(file, myImportedModule).resolveMember(name, location, direction, resolveContext);
}
else if (resolved instanceof PsiDirectory) {
final List<PsiElement> elements = Collections.singletonList(ResolveImportUtil.resolveChild(resolved, name, null, true, true));
List<PsiElement> elements = Collections.singletonList(ResolveImportUtil.resolveChild(resolved, name, null, true, true));
if (location != null && ResolveImportUtil.getPointInImport(location) == PointInImport.NONE) {
final Set<PsiElement> imported = Sets.newHashSet(PyModuleType.collectImportedSubmodules((PsiDirectory)resolved, location));
elements = ContainerUtil.filter(elements, new Condition<PsiElement>() {
@Override
public boolean value(PsiElement element) {
return imported.contains(element);
}
});
}
return ResolveImportUtil.rateResults(elements);
}
return null;
}
public Object[] getCompletionVariants(String completionPrefix, PsiElement location, ProcessingContext context) {
List<LookupElement> result = new ArrayList<LookupElement>();
ScopeOwner scopeOwner = ScopeUtil.getScopeOwner(location);
assert scopeOwner != null;
final List<PyImportElement> importTargets = PyModuleType.getVisibleImports(scopeOwner);
final int imported = myImportedModule.getImportedPrefix().getComponentCount();
for (PyImportElement importTarget : importTargets) {
final QualifiedName qName = importTarget.getImportedQName();
if (qName != null && qName.matchesPrefix(myImportedModule.getImportedPrefix())) {
final List<String> components = qName.getComponents();
if (components.size() > imported) {
String module = components.get(imported);
result.add(LookupElementBuilder.create(module));
}
}
}
final List<LookupElement> result = new ArrayList<LookupElement>();
final PsiElement resolved = myImportedModule.resolve();
if (resolved instanceof PsiDirectory) {
if (resolved instanceof PyFile) {
final PyModuleType moduleType = new PyModuleType((PyFile)resolved, myImportedModule);
result.addAll(moduleType.getCompletionVariantsAsLookupElements(location, context, false, false));
}
else if (resolved instanceof PsiDirectory) {
final PsiDirectory dir = (PsiDirectory)resolved;
if (PyUtil.isPackage(dir, location)) {
result.addAll(PyModuleType.getSubModuleVariants(dir, location, null));
if (ResolveImportUtil.getPointInImport(location) != PointInImport.NONE) {
result.addAll(PyModuleType.getSubModuleVariants(dir, location, null));
}
else {
result.addAll(PyModuleType.collectImportedSubmodulesAsLookupElements(dir, location, context.get(CTX_NAMES)));
}
}
}
return ArrayUtil.toObjectArray(result);
@@ -29,7 +29,9 @@ import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
import com.intellij.util.Function;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.PyCustomMember;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
@@ -331,7 +333,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje
result.addAll(getSubModuleVariants(myModule.getContainingDirectory(), location, namesAlready));
}
else {
addImportedSubmodules(location, namesAlready, result);
result.addAll(collectImportedSubmodulesAsLookupElements(myModule, location, namesAlready));
}
}
return result;
@@ -355,27 +357,62 @@ public class PyModuleType implements PyType { // Modules don't descend from obje
return processor;
}
private void addImportedSubmodules(PsiElement location, Set<String> existingNames, List<LookupElement> result) {
PsiFile file = location.getContainingFile();
if (file instanceof PyFile) {
PyFile pyFile = (PyFile)file;
PsiElement moduleBase = PyUtil.isPackage(myModule) ? myModule.getContainingDirectory() : myModule;
for (PyImportElement importElement : pyFile.getImportTargets()) {
PsiElement target = PyUtil.turnInitIntoDir(importElement.resolve());
if (target != null && PsiTreeUtil.isAncestor(moduleBase, target, true)) {
LookupElement element = null;
if (target instanceof PsiFileSystemItem) {
element = buildFileLookupElement((PsiFileSystemItem) target, existingNames);
}
else if (target instanceof PsiNamedElement) {
element = LookupElementBuilder.createWithIcon((PsiNamedElement)target);
}
if (element != null) {
result.add(element);
}
}
}
@NotNull
public static List<LookupElement> collectImportedSubmodulesAsLookupElements(@NotNull PsiFileSystemItem pyPackage,
@NotNull PsiElement location,
@Nullable final Set<String> existingNames) {
return ContainerUtil.mapNotNull(collectImportedSubmodules(pyPackage, location),
new Function<PsiElement, LookupElement>() {
@Override
public LookupElement fun(PsiElement element) {
if (element instanceof PsiFileSystemItem) {
return buildFileLookupElement((PsiFileSystemItem)element, existingNames);
}
else if (element instanceof PsiNamedElement) {
return LookupElementBuilder.createWithIcon((PsiNamedElement)element);
}
return null;
}
});
}
@NotNull
public static List<PsiElement> collectImportedSubmodules(@NotNull PsiFileSystemItem pyPackage, @NotNull PsiElement location) {
final PsiElement parentAnchor;
if (pyPackage instanceof PyFile && PyUtil.isPackage(((PyFile)pyPackage))) {
parentAnchor = ((PyFile)pyPackage).getContainingDirectory();
}
else if (pyPackage instanceof PsiDirectory && PyUtil.isPackage(((PsiDirectory)pyPackage), location)) {
parentAnchor = pyPackage;
}
else {
throw new IllegalArgumentException("Package argument should be either standard Python package or namespace package");
}
final ScopeOwner scopeOwner = ScopeUtil.getScopeOwner(location);
if (scopeOwner == null) {
return Collections.emptyList();
}
final List<PsiElement> result = new ArrayList<PsiElement>();
nextImportElement:
for (PyImportElement importElement : getVisibleImports(scopeOwner)) {
PsiElement resolvedChild = PyUtil.turnInitIntoDir(importElement.resolve());
if (resolvedChild == null || !PsiTreeUtil.isAncestor(parentAnchor, resolvedChild, true)) {
continue;
}
QualifiedName importedQName = importElement.getImportedQName();
// Looking for strict child of parentAncestor
while (resolvedChild != null && resolvedChild.getParent() != parentAnchor) {
if (importedQName == null || importedQName.getComponentCount() <= 1) {
continue nextImportElement;
}
importedQName = importedQName.removeTail(1);
resolvedChild = PyUtil.turnInitIntoDir(ResolveImportUtil.resolveImportElement(importElement, importedQName));
}
ContainerUtil.addIfNotNull(result, resolvedChild);
}
return result;
}
public static List<LookupElement> getSubModuleVariants(final PsiDirectory directory,
@@ -0,0 +1,3 @@
import pkg1.m1
pkg1.foo
@@ -0,0 +1,3 @@
import pkg1.m1
pkg1.f<caret>
@@ -0,0 +1,3 @@
import nspkg1.m2
nspkg1.m2
@@ -0,0 +1,3 @@
import nspkg1.m2
nspkg1.m<caret>
@@ -0,0 +1,4 @@
import pkg1.subpkg1.m1
import pkg1
pkg1.<caret>
@@ -0,0 +1,5 @@
import nspkg1.m2
print(nspkg1.m2)
print(nspkg1.<warning descr="Cannot find reference 'm3' in 'imported module nspkg1'">m3</warning>)
print(nspkg1.<warning descr="Cannot find reference 'nssubpkg1' in 'imported module nspkg1'">nssubpkg1</warning>)
@@ -136,4 +136,9 @@ public class Py3CompletionTest extends PyTestCase {
myFixture.completeBasic();
myFixture.checkResultByFile("completion/" + getTestName(true) + "/nspkg1/a.after.py");
}
// PY-14385
public void testNotImportedSubmodulesOfNamespacePackage() {
doMultiFileTest();
}
}
@@ -707,4 +707,19 @@ public class PythonCompletionTest extends PyTestCase {
assertContainsElements(suggested, PyNames.FUNCTION_SPECIAL_ATTRIBUTES);
assertDoesntContain(suggested, PyNames.METHOD_SPECIAL_ATTRIBUTES);
}
// PY-14388
public void testAttributeOfIndirectlyImportedPackage() {
doMultiFileTest();
}
// PY-14387
public void testSubmoduleOfIndirectlyImportedPackage() {
myFixture.copyDirectoryToProject("completion/" + getTestName(true), "");
myFixture.configureByFile("a.py");
myFixture.completeBasic();
final List<String> suggested = myFixture.getLookupElementStrings();
assertNotNull(suggested);
assertSameElements(suggested, "VAR", "subpkg1");
}
}
@@ -111,4 +111,9 @@ public class Py3UnresolvedReferencesInspectionTest extends PyTestCase {
public void testAttributesOfUnresolvedTypeFile() {
doTest();
}
// PY-14385
public void testNotImportedSubmodulesOfNamespacePackage() {
doMultiFileTest("main.py");
}
}