Merge remote-tracking branch 'origin/master'

This commit is contained in:
Roman Shevchenko
2014-12-16 20:24:24 +01:00
31 changed files with 322 additions and 79 deletions
@@ -169,7 +169,13 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
@Override
public void contextAction() throws Exception {
callback.evaluated(myValueDescriptor.getValueText());
final ValueDescriptorImpl fullValueDescriptor = myValueDescriptor.getFullValueDescriptor();
fullValueDescriptor.updateRepresentation(myEvaluationContext, new DescriptorLabelListener() {
@Override
public void labelChanged() {
callback.evaluated(fullValueDescriptor.getValueText());
}
});
}
});
}
@@ -42,7 +42,6 @@ import com.intellij.util.IJSwingUtilities;
import com.intellij.xdebugger.frame.XValueModifier;
import com.sun.jdi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -59,17 +58,30 @@ public class JavaValueModifier extends XValueModifier {
myJavaValue = javaValue;
}
@Nullable
@Override
public String getInitialValueEditorText() {
Value value = myJavaValue.getDescriptor().getValue();
public void calculateInitialValueEditorText(final XInitialValueCallback callback) {
final Value value = myJavaValue.getDescriptor().getValue();
if (value instanceof PrimitiveValue) {
return myJavaValue.getValueString();
callback.setValue(myJavaValue.getValueString());
}
else if (value instanceof StringReference) {
return StringUtil.wrapWithDoubleQuote(DebuggerUtils.translateStringValue(myJavaValue.getValueString()));
final EvaluationContextImpl evaluationContext = myJavaValue.getEvaluationContext();
evaluationContext.getManagerThread().schedule(new SuspendContextCommandImpl(evaluationContext.getSuspendContext()) {
@Override
public Priority getPriority() {
return Priority.NORMAL;
}
@Override
public void contextAction() throws Exception {
callback.setValue(
StringUtil.wrapWithDoubleQuote(DebuggerUtils.translateStringValue(DebuggerUtils.getValueAsString(evaluationContext, value))));
}
});
}
else {
callback.setValue(null);
}
return null;
}
//public void update(AnActionEvent e) {
@@ -22,6 +22,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.debugger.settings.NodeRendererSettings;
import com.intellij.debugger.ui.tree.DebuggerTreeNode;
@@ -58,6 +59,7 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements
private String myIdLabel;
private String myValueText;
private boolean myFullValue = false;
@Nullable
private Icon myValueIcon;
@@ -328,8 +330,32 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements
return calcValueName() + " = " + myIdLabel + myValueText;
}
public ValueDescriptorImpl getFullValueDescriptor() {
ValueDescriptorImpl descriptor = new ValueDescriptorImpl(myProject, myValue) {
@Override
public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
return myValue;
}
@Override
public String calcValueName() {
return null;
}
@Override
public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
return null;
}
};
descriptor.myFullValue = true;
return descriptor;
}
@Override
public void setValueLabel(String label) {
if (!myFullValue) {
label = DebuggerUtilsEx.truncateString(label);
}
myValueText = label;
myIdLabel = getIdLabel(label);
}
@@ -37,7 +37,6 @@ import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiExpression;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.StringBuilderSpinAllocator;
import com.intellij.xdebugger.settings.XDebuggerSettingsManager;
import com.sun.jdi.*;
import org.jdom.Element;
@@ -112,42 +111,31 @@ public class ClassRenderer extends NodeRendererImpl{
final ValueDescriptorImpl valueDescriptor = (ValueDescriptorImpl)descriptor;
final Value value = valueDescriptor.getValue();
if (value instanceof ObjectReference) {
final StringBuilder buf = StringBuilderSpinAllocator.alloc();
try {
if (value instanceof StringReference) {
// no need to add quotes and escape characters here, XValueTextRendererImpl handles the presentation
//buf.append('\"');
//buf.append(DebuggerUtils.convertToPresentationString(((StringReference)value).value()));
//buf.append('\"');
buf.append(((StringReference)value).value());
}
else if (value instanceof ClassObjectReference) {
ReferenceType type = ((ClassObjectReference)value).reflectedType();
buf.append((type != null)?type.name():"{...}");
}
else {
final ObjectReference objRef = (ObjectReference)value;
final Type type = objRef.type();
if (type instanceof ClassType && ((ClassType)type).isEnum()) {
final String name = getEnumConstantName(objRef, (ClassType)type);
if (name != null) {
buf.append(name);
}
else {
buf.append(type.name());
}
if (value instanceof StringReference) {
return ((StringReference)value).value();
}
else if (value instanceof ClassObjectReference) {
ReferenceType type = ((ClassObjectReference)value).reflectedType();
return (type != null) ? type.name() : "{...}";
}
else {
final ObjectReference objRef = (ObjectReference)value;
final Type type = objRef.type();
if (type instanceof ClassType && ((ClassType)type).isEnum()) {
final String name = getEnumConstantName(objRef, (ClassType)type);
if (name != null) {
return name;
}
else {
buf.append(ValueDescriptorImpl.getIdLabel(objRef));
return type.name();
}
}
return buf.toString();
}
finally {
StringBuilderSpinAllocator.dispose(buf);
else {
return ValueDescriptorImpl.getIdLabel(objRef);
}
}
}
else if(value == null) {
else if (value == null) {
//noinspection HardCodedStringLiteral
return "null";
}
@@ -31,7 +31,7 @@ public class SegmentArrayWithData extends SegmentArray {
}
public void setElementAt(int i, int startOffset, int endOffset, int data) {
if (data < 0 && data > Short.MAX_VALUE) throw new IndexOutOfBoundsException("data out of short range" + data);
if (data < 0 || data > Short.MAX_VALUE) throw new IndexOutOfBoundsException("data out of short range" + data);
setElementAt(i, startOffset, endOffset);
myData = reallocateArray(myData, i+1);
myData[i] = (short)data;
@@ -349,7 +349,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme {
attr.setErrorStripeColor(defaultColor);
}
}
private static final Map<String, Color> DEFAULT_ERROR_STRIPE_COLOR = new THashMap<String, Color>();
public static final Map<String, Color> DEFAULT_ERROR_STRIPE_COLOR = new THashMap<String, Color>();
static {
DEFAULT_ERROR_STRIPE_COLOR.put(CodeInsightColors.ERRORS_ATTRIBUTES.getExternalName(), Color.red);
DEFAULT_ERROR_STRIPE_COLOR.put(CodeInsightColors.WRONG_REFERENCES_ATTRIBUTES.getExternalName(), Color.red);
@@ -36,6 +36,9 @@ public interface FoldingModelEx extends FoldingModel {
boolean intersectsRegion(int startOffset, int endOffset);
/**
* @deprecated Use an equivalent method {@link FoldingModel#getCollapsedRegionAtOffset(int)} instead. To be removed in IDEA 16.
*/
FoldRegion fetchOutermost(int offset);
/**
@@ -269,7 +269,7 @@ public final class IterationState {
advanceCurrentVirtualSelectionIndex();
if (!myUseOnlyFullLineHighlighters) {
myCurrentFold = myFoldingModel.fetchOutermost(myStartOffset);
myCurrentFold = myFoldingModel.getCollapsedRegionAtOffset(myStartOffset);
}
if (myCurrentFold != null) {
myEndOffset = myCurrentFold.getEndOffset();
@@ -355,7 +355,9 @@ public class SoftWrapApplianceManager implements Dumpable {
if (!foldRegion.isValid() ||
foldRegion.getStartOffset() != myContext.tokenStartOffset
|| foldRegion.getEndOffset() > document.getTextLength()) {
LOG.error("Inconsistent fold region state: fold region: " + foldRegion + ", soft wrap model state: " + myEditor.getSoftWrapModel());
LOG.error("Inconsistent fold region state: fold region: " + foldRegion
+ ", soft wrap model state: " + myEditor.getSoftWrapModel()
+ ", folding model state: " + myEditor.getFoldingModel());
return true;
}
@@ -101,9 +101,13 @@ public class BuildInfo implements Comparable<BuildInfo> {
@Nullable
public PatchInfo findPatchForCurrentBuild() {
BuildNumber currentBuild = ApplicationInfo.getInstance().getBuild();
return findPatchForBuild(ApplicationInfo.getInstance().getBuild());
}
@Nullable
public PatchInfo findPatchForBuild(BuildNumber currentBuild) {
for (PatchInfo each : myPatches) {
if (each.isAvailable() && each.getFromBuild().asStringWithoutProductCode().equals(currentBuild.asStringWithoutProductCode()))
if (each.isAvailable() && each.getFromBuild().asStringWithoutProductCode().equals(currentBuild.asStringWithoutProductCode()))
return each;
}
return null;
@@ -89,7 +89,11 @@ public class UpdateStrategy {
for (UpdateChannel channel : channels) {
if ((channel.getMajorVersion() == myMajorVersion && channel.getStatus().compareTo(myChannelStatus) >= 0) ||
(channel.getMajorVersion() > myMajorVersion && channel.getStatus() == ChannelStatus.EAP && myChannelStatus == ChannelStatus.EAP)) {
result.add(channel);
if (channel.getMajorVersion() == myMajorVersion && channel.getStatus().compareTo(myChannelStatus) == 0) {
result.add(0, channel); // prefer channel that has same status as our selected channel status
} else {
result.add(channel);
}
}
}
return result;
@@ -116,4 +116,16 @@ public class UpdateStrategyTest extends TestCase {
Assert.assertEquals("IDEA10EAP", newChannel.getId());
Assert.assertEquals("IntelliJ IDEA X EAP", newChannel.getName());
}
public void testChannelWithCurrentStatusPreferred() {
final TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.EAP);
BuildNumber currentBuild = BuildNumber.fromString("IU-139.658");
UpdateStrategy strategy = new UpdateStrategy(14, currentBuild, UpdatesInfoXppParserTest.InfoReader.read("idea-patchAvailable.xml"), settings);
final CheckForUpdateResult result = strategy.checkForUpdates();
Assert.assertEquals(UpdateStrategy.State.LOADED, result.getState());
Assert.assertEquals(result.getUpdatedChannel().getStatus(), ChannelStatus.EAP);
Assert.assertNotNull(result.getNewBuildInSelectedChannel().findPatchForBuild(currentBuild));
}
}
@@ -0,0 +1,37 @@
<products>
<product name="IntelliJ IDEA">
<code>IU</code>
<code>IC</code>
<channel id="IDEA14" name="IntelliJ IDEA 14" status="release"
url="http://www.jetbrains.com/idea/download"
feedback="http://youtrack.jetbrains.net"
majorVersion="14">
<build number="139.659" version="14.0.2" releaseDate="20141103">
<message>IntelliJ IDEA 14.0.2 build 139.659 is available.</message>
<button name="Download" url="http://www.jetbrains.com/idea/download" download="true"/>
<button name="What's New" url="http://www.jetbrains.com/idea/whatsnew/index.html"/>
<button name="Release Notes" url="http://confluence.jetbrains.com/display/IDEADEV/IntelliJ+IDEA+14.0.2+Release+Notes"/>
<patch from="139.224" size="30" />
<patch from="139.225" size="30" />
</build>
</channel>
<channel id="IDEA_14_EAP" name="IntelliJ IDEA 14 EAP" status="eap"
url="http://confluence.jetbrains.com/display/IDEADEV/IDEA+14+EAP"
feedback="http://youtrack.jetbrains.net"
majorVersion="14">
<build number="139.659" version="14.0.2" releaseDate="20141103">
<message>IntelliJ IDEA 14.0.2 build 139.659 is available.</message>
<button name="Download" url="http://confluence.jetbrains.com/display/IDEADEV/IDEA+14+EAP" download="true"/>
<button name="Release Notes" url="http://confluence.jetbrains.com/display/IDEADEV/IntelliJ+IDEA+14+139.659.2+Release+Notes"/>
<patch from="139.658" size="10" />
<patch from="139.224" size="30" />
<patch from="139.225" size="30" />
</build>
</channel>
</product>
</products>
@@ -1040,6 +1040,17 @@ public class RangeMarkerTest extends LightPlatformTestCase {
assertTrue(marker.isValid());
}
public void testPersistentMarkerDoesntImpactNormalMarkers() {
Document doc = new DocumentImpl("text");
RangeMarker normal = doc.createRangeMarker(1, 3);
RangeMarker persistent = doc.createRangeMarker(1, 3, true);
doc.replaceString(0, 4, "before\ntext\nafter");
assertTrue(persistent.isValid());
assertFalse(normal.isValid());
}
public void testMoveTextRetargetsMarkers() throws Exception {
RangeMarkerEx marker1 = createMarker("01234567890", 1, 3);
DocumentEx document = (DocumentEx)marker1.getDocument();
@@ -46,6 +46,9 @@ public class UrlClassLoader extends ClassLoader {
@NonNls static final String CLASS_EXTENSION = ".class";
static {
// Since Java 7 classloading is parallel on parallel capable classloader (http://docs.oracle.com/javase/7/docs/technotes/guides/lang/cl-mt.html)
// Parallel classloading avoids deadlocks like https://youtrack.jetbrains.com/issue/IDEA-131621
// Unless explicitly disabled, request parallel loading capability via reflection due to current platform's Java 6 baseline
// todo[r.sh] drop condition in IDEA 15
// todo[r.sh] drop reflection after migrating to Java 7+
boolean parallelLoader = Boolean.parseBoolean(System.getProperty("idea.parallel.class.loader", "true"));
@@ -430,7 +430,17 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
myList.setSelectedIndex(listSelection);
myList.ensureIndexIsVisible(listSelection);
if (scrollRow >= 0) {
if (scrollRow == -1) {
TreeNode root = (TreeNode)model.getRoot();
int childrenCount = root.getChildCount();
TreePath[] selected = new TreePath[childrenCount];
for (int i = 0; i < childrenCount; i++) {
TreeNode child = root.getChildAt(i);
// reverse order, because the last one will become "current" node. And we want it to be the first one.
selected[childrenCount - i - 1] = new TreePath(model.getPathToRoot(child));
}
myTree.setSelectionPaths(selected);
} else {
myTree.setSelectionRow(scrollRow);
}
TreeUtil.showRowCentered(myTree, scrollRow, false);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 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.
@@ -38,7 +38,18 @@ public abstract class XValueModifier {
return null;
}
/**
* Asynchronously calculates initial value
*/
public void calculateInitialValueEditorText(XInitialValueCallback callback) {
callback.setValue(getInitialValueEditorText());
}
public interface XModificationCallback extends XValueCallback {
void valueModified();
}
public interface XInitialValueCallback {
void setValue(String initialValue);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 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.
@@ -40,7 +40,7 @@ public class SetValueInplaceEditor extends XDebuggerTreeInplaceEditor {
private final XValueModifier myModifier;
private final XValueNodeImpl myValueNode;
public SetValueInplaceEditor(final XValueNodeImpl node, @NotNull final String nodeName) {
private SetValueInplaceEditor(final XValueNodeImpl node, @NotNull final String nodeName) {
super(node, "setValue");
myValueNode = node;
myModifier = myValueNode.getValueContainer().getModifier();
@@ -57,9 +57,34 @@ public class SetValueInplaceEditor extends XDebuggerTreeInplaceEditor {
myEditorPanel.add(nameLabel, BorderLayout.WEST);
myEditorPanel.add(myExpressionEditor.getComponent(), BorderLayout.CENTER);
final String value = myModifier != null ? myModifier.getInitialValueEditorText() : null;
myExpressionEditor.setExpression(XExpressionImpl.fromText(value));
}
public static void show(final XValueNodeImpl node, @NotNull final String nodeName) {
final SetValueInplaceEditor editor = new SetValueInplaceEditor(node, nodeName);
if (editor.myModifier != null) {
editor.myModifier.calculateInitialValueEditorText(new XValueModifier.XInitialValueCallback() {
@Override
public void setValue(final String initialValue) {
AppUIUtil.invokeOnEdt(new Runnable() {
@Override
public void run() {
editor.show(initialValue);
}
});
}
});
}
else {
editor.show(null);
}
}
private void show(String initialValue) {
myExpressionEditor.setExpression(XExpressionImpl.fromText(initialValue));
myExpressionEditor.selectAll();
show();
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 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.
@@ -47,7 +47,6 @@ public class XSetValueAction extends XDebuggerTreeActionBase {
}
protected void perform(final XValueNodeImpl node, @NotNull final String nodeName, final AnActionEvent e) {
XDebuggerTreeInplaceEditor editor = new SetValueInplaceEditor(node, nodeName);
editor.show();
SetValueInplaceEditor.show(node, nodeName);
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 955 B

+9 -1
View File
@@ -91,6 +91,9 @@ target(name: "compile", description: "Compile module python") {
fileset(dir: "${ideaPlugins}/IntelliLang/lib") {
include(name: "*.jar")
}
fileset(dir: "${pluginHome}/ipnb/lib") {
include(name: "*.jar")
}
}
ant.path(id: "sourcepath") {
@@ -103,6 +106,7 @@ target(name: "compile", description: "Compile module python") {
include(name: "openapi/src")
include(name: "psi-api/src")
include(name: "IntelliLang-python/src")
include(name: "ipnb/src")
}
}
//The task requires the following libraries from IntelliJ IDEA distribution:
@@ -142,7 +146,7 @@ target(name: "compile", description: "Compile module python") {
patternset(refid: "resources.pt")
type(type: "file")
}
fileset(dir: "${pluginHome}/IntelliLang-python/src") {
fileset(dir: "${pluginHome}/IntelliLang-python/resources") {
patternset(refid: "resources.pt")
type(type: "file")
}
@@ -151,6 +155,10 @@ target(name: "compile", description: "Compile module python") {
type(type: "file")
}
fileset(dir: "${home}/colorSchemes/src")
fileset(dir: "${pluginHome}/ipnb/resources") {
patternset(refid: "resources.pt")
type(type: "file")
}
}
//copy plugin.xml
@@ -13,7 +13,7 @@ public class StudyIcons {
return IconLoader.getIcon(path, StudyIcons.class);
}
public static final Icon EducationalProjectType = load("/icons/com/jetbrains/python/edu/EducationalProjectType.png"); // 32x32
public static final Icon EducationalProjectType = load("/icons/com/jetbrains/python/edu/EducationalProjectType.png"); // 16x16
public static final Icon Lesson = load("/icons/com/jetbrains/python/edu/Lesson.png"); // 16x16
public static final Icon LessonCompl = load("/icons/com/jetbrains/python/edu/LessonCompl.png"); // 16x16
public static final Icon Prev = load("/icons/com/jetbrains/python/edu/prev.png"); // 16x16
@@ -21,7 +21,8 @@ import java.io.IOException;
public class StudyInitialConfigurator {
private static final Logger LOG = Logger.getInstance(StudyInitialConfigurator.class.getName()
);
@NonNls private static final String CONFIGURED = "StudyPyCharm.InitialConfiguration";
@NonNls private static final String CONFIGURED_V1 = "StudyPyCharm.InitialConfiguration";
@NonNls private static final String CONFIGURED_V11 = "StudyPyCharm.InitialConfiguration1.1";
/**
@@ -34,21 +35,38 @@ public class StudyInitialConfigurator {
FileTypeManager fileTypeManager,
final ProjectManagerEx projectManager,
RecentProjectsManager recentProjectsManager) {
if (!propertiesComponent.getBoolean(CONFIGURED, false)) {
final File file = new File(getCoursesRoot(), "introduction_course.zip");
final File file = new File(getCoursesRoot(), "introduction_course.zip");
if (!propertiesComponent.getBoolean(CONFIGURED_V1, false)) {
final File newCourses = new File(PathManager.getConfigPath(), "courses");
try {
FileUtil.createDirectory(newCourses);
String fileName = file.getName();
String unzippedName = fileName.substring(0, fileName.indexOf("."));
File courseDir = new File(newCourses, unzippedName);
ZipUtil.unzip(null, courseDir, file, null, null, true);
copyCourse(file, newCourses);
propertiesComponent.setValue(CONFIGURED_V1, "true");
}
catch (IOException e) {
LOG.warn("Couldn't copy bundled courses " + e);
}
}
if (!propertiesComponent.getBoolean(CONFIGURED_V11, false)) {
final File newCourses = new File(PathManager.getConfigPath(), "courses");
if (newCourses.exists()) {
try {
copyCourse(file, newCourses);
propertiesComponent.setValue(CONFIGURED_V11, "true");
}
catch (IOException e) {
LOG.warn("Couldn't copy bundled courses " + e);
}
}
}
}
private static void copyCourse(File bundledCourse, File userCourseDir) throws IOException {
String fileName = bundledCourse.getName();
String unzippedName = fileName.substring(0, fileName.indexOf("."));
File courseDir = new File(userCourseDir, unzippedName);
ZipUtil.unzip(null, courseDir, bundledCourse, null, null, true);
}
public static File getCoursesRoot() {
@@ -67,6 +67,7 @@ should import it explicitly. For example, in a skeleton for the `foo` module:
```python
import foo
class C(foo.B):
def bar():
"""Do bar and return Bar.
@@ -144,6 +145,7 @@ class C(object):
pass
```
### Versioning
The recommended way of checking the version of Python is:
@@ -151,10 +153,12 @@ The recommended way of checking the version of Python is:
```python
import sys
if sys.version_info >= (2, 7) and sys.version_info < (3,):
def from_27_until_30():
pass
```
A skeleton should document the most recently released version of a library. Use
deprecation warnings for functions that have been removed from the API.
@@ -214,6 +218,7 @@ the skeletons GitHub repository into your PyCharm/IntelliJ config directory:
cd <config directory>
git clone https://github.com/JetBrains/python-skeletons.git
```
where `<config directory>` is:
* PyCharm
@@ -427,6 +427,24 @@ class int(object):
"""
pass
def __eq__(self, y):
return False
def __ne__(self, y):
return False
def __lt__(self, y):
return False
def __gt__(self, y):
return False
def __le__(self, y):
return False
def __ge__(self, y):
return False
def __add__(self, y):
"""Sum of x and y.
@@ -15,7 +15,6 @@
*/
package com.jetbrains.python.codeInsight.userSkeletons;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
@@ -24,7 +23,6 @@ import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
@@ -65,9 +63,7 @@ public class PyUserSkeletonsUtil {
private static List<String> getPossibleUserSkeletonsPaths() {
final List<String> result = new ArrayList<String>();
result.add(PathManager.getConfigPath() + File.separator + USER_SKELETONS_DIR);
result.add(ApplicationManager.getApplication().isInternal()
? StringUtil.join(new String[]{PythonHelpersLocator.getPythonCommunityPath(), "helpers", USER_SKELETONS_DIR}, File.separator)
: PythonHelpersLocator.getHelperPath(USER_SKELETONS_DIR));
result.add(PythonHelpersLocator.getHelperPath(USER_SKELETONS_DIR));
return result;
}
@@ -133,7 +133,7 @@ public class PyTypeCheckerInspection extends PyInspection {
String msg= String.format("Expected type %s, got '%s' instead", quotedExpectedName, actualName);
if (expected instanceof PyStructuralType) {
final Set<String> expectedAttributes = ((PyStructuralType)expected).getAttributeNames();
final Set<String> actualAttributes = getAttributes(actual);
final Set<String> actualAttributes = getAttributes(actual, context);
if (actualAttributes != null) {
final Sets.SetView<String> missingAttributes = Sets.difference(expectedAttributes, actualAttributes);
if (missingAttributes.size() == 1) {
@@ -160,12 +160,12 @@ public class PyTypeCheckerInspection extends PyInspection {
}
@Nullable
private static Set<String> getAttributes(@NotNull PyType type) {
private static Set<String> getAttributes(@NotNull PyType type, @NotNull TypeEvalContext context) {
if (type instanceof PyStructuralType) {
return ((PyStructuralType)type).getAttributeNames();
}
else if (type instanceof PyClassType) {
return PyTypeChecker.getClassAttributes(((PyClassType)type).getPyClass(), true);
return PyTypeChecker.getClassTypeAttributes((PyClassType)type, true, context);
}
return null;
}
@@ -1190,7 +1190,23 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
continue;
}
final PyType type = context.getType(expression);
result.add(type instanceof PyClassLikeType ? (PyClassLikeType)type : null);
PyClassLikeType classLikeType = null;
if (type instanceof PyClassLikeType) {
classLikeType = (PyClassLikeType)type;
}
else {
final PsiReference ref = expression.getReference();
if (ref != null) {
final PsiElement resolved = ref.resolve();
if (resolved instanceof PyClass) {
final PyType resolvedType = context.getType((PyClass)resolved);
if (resolvedType instanceof PyClassLikeType) {
classLikeType = (PyClassLikeType)resolvedType;
}
}
}
}
result.add(classLikeType);
}
}
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(this);
@@ -15,11 +15,13 @@
*/
package com.jetbrains.python.psi.types;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.PsiReference;
import com.intellij.psi.ResolveResult;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.PyCustomMember;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.resolve.PyResolveContext;
@@ -167,15 +169,15 @@ public class PyTypeChecker {
return expectedStructural.getAttributeNames().containsAll(actualStructural.getAttributeNames());
}
if (expected instanceof PyStructuralType && actual instanceof PyClassType) {
final PyClass cls = ((PyClassType)actual).getPyClass();
if (overridesGetAttr(cls, context)) {
final PyClassType actualClassType = (PyClassType)actual;
if (overridesGetAttr(actualClassType.getPyClass(), context)) {
return true;
}
final Set<String> actualAttributes = getClassAttributes(cls, true);
final Set<String> actualAttributes = getClassTypeAttributes(actualClassType, true, context);
return actualAttributes.containsAll(((PyStructuralType)expected).getAttributeNames());
}
if (actual instanceof PyStructuralType && expected instanceof PyClassType) {
final Set<String> expectedAttributes = getClassAttributes(((PyClassType)expected).getPyClass(), true);
final Set<String> expectedAttributes = getClassTypeAttributes((PyClassType)expected, true, context);
return expectedAttributes.containsAll(((PyStructuralType)actual).getAttributeNames());
}
if (actual instanceof PyCallableType && expected instanceof PyCallableType) {
@@ -205,7 +207,19 @@ public class PyTypeChecker {
}
@NotNull
public static Set<String> getClassAttributes(@NotNull PyClass cls, boolean inherited) {
public static Set<String> getClassTypeAttributes(@NotNull PyClassType type, boolean inherited, @NotNull TypeEvalContext context) {
final Set<String> attributes = getClassAttributes(type.getPyClass(), inherited, context);
for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) {
final Collection<PyCustomMember> members = provider.getMembers(type, null);
for (PyCustomMember member : members) {
attributes.add(member.getName());
}
}
return attributes;
}
@NotNull
private static Set<String> getClassAttributes(@NotNull PyClass cls, boolean inherited, @NotNull TypeEvalContext context) {
final Set<String> attributes = new HashSet<String>();
for (PyFunction function : cls.getMethods(false)) {
attributes.add(function.getName());
@@ -218,7 +232,10 @@ public class PyTypeChecker {
}
if (inherited) {
for (PyClass ancestor : cls.getAncestorClasses()) {
attributes.addAll(getClassAttributes(ancestor, false));
final PyType ancestorType = context.getType(ancestor);
if (ancestorType instanceof PyClassType) {
attributes.addAll(getClassTypeAttributes((PyClassType)ancestorType, false, context));
}
}
}
return attributes;
@@ -0,0 +1,8 @@
def f(x):
print(x < 0, x <= 0, x > 0, x >= 0, x != 0)
print(x.foo)
print(f(<warning descr="Type 'bool' doesn't have expected attribute 'foo'">True</warning>))
print(f(<warning descr="Type 'int' doesn't have expected attribute 'foo'">0</warning>))
print(f(<warning descr="Type 'float' doesn't have expected attribute 'foo'">3.14</warning>))
@@ -267,4 +267,8 @@ public class PyTypeCheckerInspectionTest extends PyTestCase {
public void testGetAttributeAgainstStructuralType() {
doTest();
}
public void testComparisonOperatorsForNumericTypes() {
doTest();
}
}