Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2011-11-22 10:07:39 +01:00
42 changed files with 378 additions and 89 deletions
@@ -8,6 +8,7 @@ import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.MultiLineLabelUI;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -26,7 +27,7 @@ public class PythonSdkChooserPanel extends JComponent {
*
* @param project Current project
*/
public PythonSdkChooserPanel(final Project project) {
public PythonSdkChooserPanel(@NotNull final Project project) {
myJdkChooser = new JdkChooserPanel(project);
setLayout(new GridBagLayout());
@@ -6,6 +6,7 @@
<extensions defaultExtensionNs="com.intellij">
<errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
<fileTypeFactory implementation="com.jetbrains.python.PythonFileTypeFactory"/>
<fileTypeDetector implementation="com.jetbrains.python.PyFileTypeDetector"/>
<lang.syntaxHighlighterFactory key="Python" implementationClass="com.jetbrains.python.highlighting.PySyntaxHighlighterFactory"/>
<lang.braceMatcher language="Python" implementationClass="com.jetbrains.python.PyBraceMatcher"/>
<lang.parserDefinition language="Python" implementationClass="com.jetbrains.python.PythonParserDefinition"/>
@@ -383,6 +384,8 @@
<projectConfigurable instance="com.jetbrains.python.console.PyConsoleOptionsConfigurable"/>
<projectService serviceImplementation="com.jetbrains.python.console.PyConsoleOptionsProvider"/>
<codeBlockProvider language="Python" implementationClass="com.jetbrains.python.codeInsight.PyCodeBlockProvider"/>
<!-- Cython -->
<lang.parserDefinition language="Cython" implementationClass="com.jetbrains.cython.parser.CythonParserDefinition"/>
<lang.syntaxHighlighterFactory key="Cython" implementationClass="com.jetbrains.cython.CythonSyntaxHighlighterFactory"/>
@@ -0,0 +1,33 @@
package com.jetbrains.python;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.openapi.util.io.ByteSequence;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public class PyFileTypeDetector implements FileTypeRegistry.FileTypeDetector {
@Override
public FileType detect(@NotNull VirtualFile file, @NotNull ByteSequence firstBytes, @Nullable CharSequence firstCharsIfText) {
if (firstCharsIfText == null) {
return null;
}
final int lineBreak = StringUtil.indexOf(firstCharsIfText, '\n');
if (lineBreak < 0) {
return null;
}
String firstLine = firstCharsIfText.subSequence(0, lineBreak).toString();
if (!firstLine.startsWith("#!")) {
return null;
}
if (firstLine.contains("python")) {
return PythonFileType.INSTANCE;
}
return null;
}
}
@@ -3,9 +3,11 @@ package com.jetbrains.python.actions;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.TokenSet;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.PyBinaryExpression;
import com.jetbrains.python.psi.PyElementGenerator;
import com.jetbrains.python.psi.PyExpression;
@@ -18,12 +20,10 @@ import org.jetbrains.annotations.NotNull;
* Time: 19:41:07
*/
public class SimplifyBooleanCheckQuickFix implements LocalQuickFix {
private PyBinaryExpression myExpression;
private String myReplacementText;
public SimplifyBooleanCheckQuickFix(PyBinaryExpression binaryExpression) {
myExpression = binaryExpression;
myReplacementText = createReplacementText();
myReplacementText = createReplacementText(binaryExpression);
}
private static boolean isTrue(PyExpression expression) {
@@ -53,15 +53,19 @@ public class SimplifyBooleanCheckQuickFix implements LocalQuickFix {
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
if (!element.isValid() || !(element instanceof PyBinaryExpression)) {
return;
}
PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
myExpression.replace(elementGenerator.createExpressionFromText(myReplacementText));
element.replace(elementGenerator.createExpressionFromText(LanguageLevel.forElement(element), myReplacementText));
}
private String createReplacementText() {
private static String createReplacementText(PyBinaryExpression expression) {
PyExpression resultExpression;
final PyExpression leftExpression = myExpression.getLeftExpression();
final PyExpression rightExpression = myExpression.getRightExpression();
boolean positiveCondition = !TokenSet.create(PyTokenTypes.NE, PyTokenTypes.NE_OLD).contains(myExpression.getOperator());
final PyExpression leftExpression = expression.getLeftExpression();
final PyExpression rightExpression = expression.getRightExpression();
boolean positiveCondition = !TokenSet.create(PyTokenTypes.NE, PyTokenTypes.NE_OLD).contains(expression.getOperator());
positiveCondition ^= isFalse(leftExpression) || isFalse(rightExpression) || isNull(rightExpression) || isNull(leftExpression)
|| isEmpty(rightExpression) || isEmpty(leftExpression);
if (isTrue(leftExpression) || isFalse(leftExpression) || isNull(leftExpression) || isEmpty(leftExpression)) {
@@ -0,0 +1,55 @@
package com.jetbrains.python.codeInsight;
import com.intellij.codeInsight.editorActions.CodeBlockProvider;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.psi.PyStatement;
import com.jetbrains.python.psi.PyStatementList;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public class PyCodeBlockProvider implements CodeBlockProvider {
@Nullable
@Override
public TextRange getCodeBlockRange(Editor editor, PsiFile psiFile) {
int caretOffset = editor.getCaretModel().getOffset();
PsiElement element = psiFile.findElementAt(caretOffset);
if (element == null) {
return null;
}
while (caretOffset > 0 && element instanceof PsiWhiteSpace) {
caretOffset--;
element = psiFile.findElementAt(caretOffset);
}
PyStatement statement = PsiTreeUtil.getParentOfType(element, PyStatement.class);
if (statement != null) {
PyStatementList statementList = PsiTreeUtil.findChildOfType(statement, PyStatementList.class);
// if the statement above caret is not a block statement, look above for a statement list and then find the statement above
// that statement list
if (statementList == null) {
statementList = PsiTreeUtil.getParentOfType(statement, PyStatementList.class);
if (statementList != null) {
statement = PsiTreeUtil.getParentOfType(statementList, PyStatement.class);
}
}
if (statement != null) {
// if we're in the beginning of the statement already, pressing Ctrl-[ again should move the caret one statement higher
if (caretOffset == statement.getTextRange().getStartOffset()) {
final PyStatement statementAbove = PsiTreeUtil.getParentOfType(statement, PyStatement.class);
if (statementAbove != null) {
return new TextRange(statementAbove.getTextRange().getStartOffset(), statement.getTextRange().getEndOffset());
}
}
return statement.getTextRange();
}
}
return null;
}
}
@@ -362,9 +362,9 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
}
@Nullable
public static String pyVersion(String versionString) {
public static String pyVersion(@Nullable String versionString) {
String prefix = "Python ";
if (versionString.startsWith(prefix)) {
if (versionString != null && versionString.startsWith(prefix)) {
String version = versionString.substring(prefix.length());
int dot = version.indexOf('.');
if (dot > 0) {
@@ -9,6 +9,7 @@ import com.jetbrains.python.PyBundle;
import com.jetbrains.python.actions.RemoveArgumentEqualDefaultQuickFix;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.types.PyClassType;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -52,19 +53,36 @@ public class PyArgumentEqualDefaultInspection extends PyInspection {
}
@Override
public void visitPyCallExpression(final PyCallExpression node){
public void visitPyCallExpression(final PyCallExpression node) {
PyArgumentList list = node.getArgumentList();
PyCallExpression.PyMarkedCallee func = node.resolveCallee(resolveWithoutImplicits());
if ((func != null && func.isImplicitlyResolved()) || (list == null)) return;
if (func != null) {
// getattr's default attribute is a special case, see PY-3440
final Callable callable = func.getCallable();
if ("getattr".equals(callable.getName()) && PyBuiltinCache.getInstance(node).hasInBuiltins(callable)) return;
if (hasSpecialCasedDefaults(callable, node)) {
return;
}
}
CallArgumentsMapping result = list.analyzeCall(resolveWithoutImplicits());
checkArguments(result, node.getArguments());
}
private static boolean hasSpecialCasedDefaults(Callable callable, PsiElement anchor) {
final String name = callable.getName();
final PyBuiltinCache cache = PyBuiltinCache.getInstance(anchor);
if ("getattr".equals(name) && cache.hasInBuiltins(callable)) {
return true;
}
else if ("get".equals(name) || "pop".equals(name)) {
final PyFunction method = callable.asMethod();
final PyClassType dictType = cache.getDictType();
if (method != null && dictType != null && method.getContainingClass() == dictType.getPyClass()) {
return true;
}
}
return false;
}
private void checkArguments(CallArgumentsMapping result, PyExpression[] arguments) {
Map<PyExpression, PyNamedParameter> mapping = result.getPlainMappedParams();
Set<PyExpression> problemElements = new HashSet<PyExpression>();
@@ -400,7 +400,8 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
PyType qtype = myTypeEvalContext.getType(qualifier);
if (qtype != null) {
if (qtype instanceof PyNoneType || qtype instanceof PyTypeReference ||
(qtype instanceof PyUnionType && ((PyUnionType) qtype).isWeak())) {
(qtype instanceof PyUnionType && ((PyUnionType) qtype).isWeak()) ||
(qtype instanceof PyImportedModuleType)) {
// this almost always means that we don't know the type, so don't show an error in this case
return;
}
@@ -174,6 +174,9 @@ public class PythonIndentingProcessor extends MergingLexerAdapter {
adjustBraceLevel();
myLineHasSignificantTokens = false;
checkSignificantTokens();
if (isBaseAt(PyTokenTypes.SPACE)) {
processIndent(0, PyTokenTypes.SPACE);
}
}
private void adjustBraceLevel() {
@@ -254,7 +257,7 @@ public class PythonIndentingProcessor extends MergingLexerAdapter {
}
myLineHasSignificantTokens = false;
advanceBase();
processIndent(startPos);
processIndent(startPos, PyTokenTypes.LINE_BREAK);
}
else {
processInsignificantLineBreak(startPos, false);
@@ -281,7 +284,7 @@ public class PythonIndentingProcessor extends MergingLexerAdapter {
myTokenQueue.add(new PendingToken(PyTokenTypes.LINE_BREAK, startPos, end));
}
protected void processIndent(int whiteSpaceStart) {
protected void processIndent(int whiteSpaceStart, IElementType whitespaceTokenType) {
int lastIndent = myIndentStack.peek();
int indent = getNextLineIndent();
myLastNewLineIndent = indent;
@@ -292,7 +295,7 @@ public class PythonIndentingProcessor extends MergingLexerAdapter {
int whiteSpaceEnd = (getBaseTokenType() == null) ? super.getBufferEnd() : getBaseTokenStart();
if (indent > lastIndent) {
myIndentStack.push(indent);
myTokenQueue.add(new PendingToken(PyTokenTypes.LINE_BREAK, whiteSpaceStart, whiteSpaceEnd));
myTokenQueue.add(new PendingToken(whitespaceTokenType, whiteSpaceStart, whiteSpaceEnd));
int insertIndex = skipPrecedingCommentsWithIndent(indent, myTokenQueue.size() - 1);
int indentOffset = insertIndex == myTokenQueue.size() ? whiteSpaceEnd : myTokenQueue.get(insertIndex).getStart();
myTokenQueue.add(insertIndex, new PendingToken(PyTokenTypes.INDENT, indentOffset, indentOffset));
@@ -315,10 +318,10 @@ public class PythonIndentingProcessor extends MergingLexerAdapter {
}
myTokenQueue.add(insertIndex, new PendingToken(PyTokenTypes.DEDENT, dedentOffset, dedentOffset));
}
myTokenQueue.add(new PendingToken(PyTokenTypes.LINE_BREAK, whiteSpaceStart, whiteSpaceEnd));
myTokenQueue.add(new PendingToken(whitespaceTokenType, whiteSpaceStart, whiteSpaceEnd));
}
else {
myTokenQueue.add(new PendingToken(PyTokenTypes.LINE_BREAK, whiteSpaceStart, whiteSpaceEnd));
myTokenQueue.add(new PendingToken(whitespaceTokenType, whiteSpaceStart, whiteSpaceEnd));
}
}
@@ -307,7 +307,7 @@ public class ExpressionParsing extends Parsing {
else recast_first_identifier = false;
myBuilder.advanceLexer();
checkMatches(PyTokenTypes.IDENTIFIER, message("PARSE.expected.name"));
if (isTargetExpression && ! recast_qualifier && myBuilder.getTokenType() != PyTokenTypes.DOT) {
if (isTargetExpression && ! recast_qualifier && !atAnyOfTokens(PyTokenTypes.DOT, PyTokenTypes.LPAR, PyTokenTypes.LBRACKET)) {
expr.done(PyElementTypes.TARGET_EXPRESSION);
}
else {
@@ -551,17 +551,13 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
final PsiBuilder.Marker ifPart = myBuilder.mark();
myBuilder.advanceLexer();
getExpressionParser().parseExpression();
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
ifPart.done(PyElementTypes.IF_PART_IF);
PsiBuilder.Marker elifPart = myBuilder.mark();
while (myBuilder.getTokenType() == elifKeyword) {
myBuilder.advanceLexer();
getExpressionParser().parseExpression();
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
elifPart.done(PyElementTypes.IF_PART_ELIF);
elifPart = myBuilder.mark();
}
@@ -569,9 +565,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
final PsiBuilder.Marker elsePart = myBuilder.mark();
if (myBuilder.getTokenType() == elseKeyword) {
myBuilder.advanceLexer();
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
elsePart.done(PyElementTypes.ELSE_PART);
}
else elsePart.drop();
@@ -598,9 +592,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
final PsiBuilder.Marker elsePart = myBuilder.mark();
if (myBuilder.getTokenType() == PyTokenTypes.ELSE_KEYWORD) {
myBuilder.advanceLexer();
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
elsePart.done(PyElementTypes.ELSE_PART);
}
else elsePart.drop();
@@ -613,9 +605,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
getExpressionParser().parseExpression(true, true);
checkMatches(PyTokenTypes.IN_KEYWORD, "'in' expected");
getExpressionParser().parseExpression();
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
forPart.done(PyElementTypes.FOR_PART);
}
@@ -627,16 +617,12 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
if (!getExpressionParser().parseSingleExpression(false)) {
myBuilder.error("expression expected");
}
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
whilePart.done(PyElementTypes.WHILE_PART);
final PsiBuilder.Marker elsePart = myBuilder.mark();
if (myBuilder.getTokenType() == PyTokenTypes.ELSE_KEYWORD) {
myBuilder.advanceLexer();
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
elsePart.done(PyElementTypes.ELSE_PART);
}
else elsePart.drop();
@@ -648,9 +634,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
final PsiBuilder.Marker statement = myBuilder.mark();
final PsiBuilder.Marker tryPart = myBuilder.mark();
myBuilder.advanceLexer();
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
tryPart.done(PyElementTypes.TRY_PART);
boolean haveExceptClause = false;
if (myBuilder.getTokenType() == PyTokenTypes.EXCEPT_KEYWORD) {
@@ -670,17 +654,13 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
}
}
}
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
exceptBlock.done(PyElementTypes.EXCEPT_PART);
}
final PsiBuilder.Marker elsePart = myBuilder.mark();
if (myBuilder.getTokenType() == PyTokenTypes.ELSE_KEYWORD) {
myBuilder.advanceLexer();
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
elsePart.done(PyElementTypes.ELSE_PART);
}
else elsePart.drop();
@@ -688,9 +668,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
final PsiBuilder.Marker finallyPart = myBuilder.mark();
if (myBuilder.getTokenType() == PyTokenTypes.FINALLY_KEYWORD) {
myBuilder.advanceLexer();
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
finallyPart.done(PyElementTypes.FINALLY_PART);
}
else {
@@ -704,6 +682,16 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
statement.done(PyElementTypes.TRY_EXCEPT_STATEMENT);
}
private void parseColonAndSuite(ParsingScope scope) {
if (expectColon()) {
parseSuite(scope);
}
else {
final PsiBuilder.Marker mark = myBuilder.mark();
mark.done(PyElementTypes.STATEMENT_LIST);
}
}
private void parseWithStatement(ParsingScope scope) {
assertCurrentToken(PyTokenTypes.WITH_KEYWORD);
final PsiBuilder.Marker statement = myBuilder.mark();
@@ -721,9 +709,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
break;
}
}
if (expectColon()) {
parseSuite(scope);
}
parseColonAndSuite(scope);
statement.done(PyElementTypes.WITH_STATEMENT);
}
@@ -743,13 +729,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
final PsiBuilder.Marker inheritMarker = myBuilder.mark();
inheritMarker.done(PyElementTypes.ARGUMENT_LIST);
}
if (expectColon()) {
parseSuite(scope.withClass(true));
}
else {
final PsiBuilder.Marker mark = myBuilder.mark();
mark.done(PyElementTypes.STATEMENT_LIST);
}
parseColonAndSuite(scope.withClass(true));
classMarker.done(PyElementTypes.CLASS_DECLARATION);
}
@@ -41,6 +41,11 @@ public abstract class PyElementGenerator {
public abstract PyBinaryExpression createBinaryExpression(String s, PyExpression expr, PyExpression listLiteral);
/**
* @deprecated use the overload with language level specified
* @param text the text to create an expression from
* @return the expression
*/
@Nullable
public abstract PyExpression createExpressionFromText(String text);
@@ -44,7 +44,7 @@ public class PyFileElementType extends IStubFileElementType<PyFileStub> {
@Override
public int getStubVersion() {
return 36;
return 37;
}
@Override
@@ -1,5 +1,6 @@
package com.jetbrains.python.psi.impl;
import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
@@ -179,7 +180,7 @@ public class PyCallExpressionImpl extends PyElementImpl implements PyCallExpress
if (second_type instanceof PyClassType) {
// imitate isinstance(second_arg, possible_class)
PyClass second_class = ((PyClassType)second_type).getPyClass();
if (first_class == second_class) {
if (CompletionUtil.getOriginalOrSelf(first_class) == second_class) {
return getSuperClassUnionType(first_class);
}
if (second_class != null && second_class.isSubclass(first_class)) {
@@ -1,6 +1,8 @@
package com.jetbrains.python.psi.impl;
import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
@@ -832,12 +834,12 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
// __init__ takes priority over all other methods
PyFunctionImpl initMethod = (PyFunctionImpl)findMethodByName(PyNames.INIT, false);
if (initMethod != null) {
collectInstanceAttributes(initMethod, result);
collectInstanceAttributes(initMethod, result, null);
}
final PyFunction[] methods = getMethods();
for (PyFunction method : methods) {
if (!PyNames.INIT.equals(method.getName())) {
collectInstanceAttributes(method, result);
collectInstanceAttributes(method, result, null);
}
}
@@ -845,7 +847,9 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
return new ArrayList<PyTargetExpression>(expressions);
}
private static void collectInstanceAttributes(PyFunction method, final Map<String, PyTargetExpression> result) {
private static void collectInstanceAttributes(@NotNull PyFunction method,
@NotNull final Map<String, PyTargetExpression> result,
@Nullable PsiElement anchor) {
final PyParameter[] params = method.getParameterList().getParameters();
if (params.length == 0) {
return;
@@ -859,25 +863,49 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
}
}
}
else if (anchor != null) {
PyResolveUtil.treeCrawlUp(new PsiScopeProcessor() {
@Override
public boolean execute(PsiElement element, ResolveState state) {
if (element instanceof PyAssignmentStatement) {
collectNewTargets(result, (PyAssignmentStatement)element);
}
return true;
}
@Nullable
@Override
public <T> T getHint(Key<T> hintKey) {
return null;
}
@Override
public void handleEvent(Event event, @Nullable Object associated) {
}
}, false, anchor, method);
}
else {
// NOTE: maybe treeCrawlUp would be more precise, but currently it works well enough; don't care.
final PyStatementList statementList = method.getStatementList();
if (statementList != null) {
statementList.accept(new PyRecursiveElementVisitor() {
public void visitPyAssignmentStatement(final PyAssignmentStatement node) {
super.visitPyAssignmentStatement(node);
final PyExpression[] targets = node.getTargets();
for (PyExpression target : targets) {
if (PyUtil.isInstanceAttribute(target) && !result.containsKey(target.getName())) {
result.put(target.getName(), (PyTargetExpression) target);
}
}
collectNewTargets(result, node);
}
});
}
}
}
private static void collectNewTargets(Map<String, PyTargetExpression> collected, PyAssignmentStatement node) {
final PyExpression[] targets = node.getTargets();
for (PyExpression target : targets) {
if (target instanceof PyTargetExpression && PyUtil.isInstanceAttribute(target) && !collected.containsKey(target.getName())) {
collected.put(target.getName(), (PyTargetExpression)target);
}
}
}
public boolean isNewStyleClass() {
return myNewStyle.getValue().getValue();
}
@@ -947,8 +975,9 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
public boolean processInstanceLevelDeclarations(PsiScopeProcessor processor, @Nullable PyExpression location) {
Map<String, PyTargetExpression> declarationsInMethod = new HashMap<String, PyTargetExpression>();
PyFunction instanceMethod = PsiTreeUtil.getParentOfType(location, PyFunction.class);
if (instanceMethod != null && instanceMethod.getContainingClass() == this) {
collectInstanceAttributes(instanceMethod, declarationsInMethod);
final PyClass containingClass = instanceMethod != null ? instanceMethod.getContainingClass() : null;
if (instanceMethod != null && containingClass != null && CompletionUtil.getOriginalElement(containingClass) == this) {
collectInstanceAttributes(instanceMethod, declarationsInMethod, location);
for (PyTargetExpression targetExpression : declarationsInMethod.values()) {
if (!processor.execute(targetExpression, ResolveState.initial())) {
return false;
@@ -13,6 +13,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.PyDynamicMember;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
@@ -270,7 +271,7 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType {
if (containingClass != null) {
containingClass = CompletionUtil.getOriginalElement(containingClass);
}
boolean withinOurClass = containingClass == getPyClass();
boolean withinOurClass = containingClass == getPyClass() || isInSuperCall(expressionHook);
final CompletionVariantsProcessor processor = new CompletionVariantsProcessor(
expressionHook, new PyResolveUtil.FilterNotInstance(myClass), null
@@ -303,6 +304,14 @@ public class PyClassType extends UserDataHolderBase implements PyCallableType {
}
}
private static boolean isInSuperCall(PyExpression hook) {
if (hook instanceof PyReferenceExpression) {
final PyExpression qualifier = ((PyReferenceExpression)hook).getQualifier();
return qualifier instanceof PyCallExpression && ((PyCallExpression) qualifier).isCalleeText(PyNames.SUPER);
}
return false;
}
private void addInheritedMembers(String name, PyExpression expressionHook, ProcessingContext context, List<Object> ret) {
for (PyClass ancestor : myClass.getSuperClasses()) {
Object[] ancestry = (new PyClassType(ancestor, true)).getCompletionVariants(name, expressionHook, context);
@@ -361,6 +361,9 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
final PyAssignmentStatement statement = performRefactoring(operation);
PyTargetExpression target = (PyTargetExpression) statement.getTargets() [0];
final List<PsiElement> occurrences = operation.getOccurrences();
if (occurrences.size() == 0) {
operation.getEditor().getCaretModel().moveToOffset(target.getTextRange().getStartOffset());
}
final InplaceVariableIntroducer<PsiElement> introducer =
new PyInplaceVariableIntroducer(target, operation, occurrences);
introducer.performInplaceRename(false, new LinkedHashSet<String>(operation.getSuggestedNames()));
@@ -0,0 +1,7 @@
package com.jetbrains.python.sdk;
/**
* @author yole
*/
public abstract class CPythonSdkFlavor extends PythonSdkFlavor {
}
@@ -10,7 +10,7 @@ import java.util.List;
/**
* @author yole
*/
public class MacPythonSdkFlavor extends PythonSdkFlavor {
public class MacPythonSdkFlavor extends CPythonSdkFlavor {
private MacPythonSdkFlavor() {
}
@@ -349,7 +349,6 @@ public class PythonSdkType extends SdkType {
}
private boolean switchPathToInterpreter(Sdk currentSdk, String... variants) {
final Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
File sdk_file = new File(currentSdk.getHomePath());
final String sdk_name = currentSdk.getName();
boolean success = false;
@@ -369,7 +368,7 @@ public class PythonSdkType extends SdkType {
if (!success) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
Messages.showWarningDialog(project,
Messages.showWarningDialog(
"Failed to convert Python SDK '" + sdk_name + "'\nplease delete and re-create it",
"Converting Python SDK"
);
@@ -10,7 +10,7 @@ import java.util.List;
/**
* @author yole
*/
public class UnixPythonSdkFlavor extends PythonSdkFlavor {
public class UnixPythonSdkFlavor extends CPythonSdkFlavor {
private UnixPythonSdkFlavor() {
}
@@ -13,7 +13,7 @@ import java.util.TreeSet;
/**
* @author yole
*/
public class WinPythonSdkFlavor extends PythonSdkFlavor {
public class WinPythonSdkFlavor extends CPythonSdkFlavor {
public static WinPythonSdkFlavor INSTANCE = new WinPythonSdkFlavor();
private WinPythonSdkFlavor() {
@@ -0,0 +1,9 @@
class C1(object):
def method1(self):
pass
class Test(object):
def __init__(self, x):
self.x = x
self.x = C1()
self.x.method1()
@@ -0,0 +1,9 @@
class C1(object):
def method1(self):
pass
class Test(object):
def __init__(self, x):
self.x = x
self.x = C1()
self.x.meth<caret>
@@ -0,0 +1,8 @@
class Matrix(object):
def __init__(self):
pass
class Vector3(Matrix):
def __init__(self):
super(Vector3, self).__init__()
+8
View File
@@ -0,0 +1,8 @@
class Matrix(object):
def __init__(self):
pass
class Vector3(Matrix):
def __init__(self):
super(Vector3, self).__in<caret>
@@ -3,9 +3,6 @@ def foo(a, b = 345, c = 1):
foo(1, <warning descr="Argument equals to default parameter value">345</warning>, 22)
a = dict()
a.get(1, <warning descr="Argument equals to default parameter value">None</warning>)
def foo(a = None):
pass
foo(<warning descr="Argument equals to default parameter value">a = None</warning>)
@@ -67,3 +64,6 @@ kw = a()
kw['customerPaymentProfileId'] = kw.get("customerPaymentProfileId",
<warning descr="Argument equals to default parameter value">None</warning>)
{1: 2}.get('foo', None) #pass
{1: 2}.pop('foo', None) #pass
@@ -0,0 +1,2 @@
import <warning descr="Unresolved reference 'deliverance'">deliverance</warning>.proxycommand
deliverance.proxycommand.main()
+1
View File
@@ -0,0 +1 @@
etree.SubElement(dictionary, u'Name').text = dict_name
+25
View File
@@ -0,0 +1,25 @@
PyFile:CallInAssignment.py
PyAssignmentStatement
PyTargetExpression: text
PyCallExpression: etree.SubElement
PyReferenceExpression: SubElement
PyReferenceExpression: etree
PsiElement(Py:IDENTIFIER)('etree')
PsiElement(Py:DOT)('.')
PsiElement(Py:IDENTIFIER)('SubElement')
PyArgumentList
PsiElement(Py:LPAR)('(')
PyReferenceExpression: dictionary
PsiElement(Py:IDENTIFIER)('dictionary')
PsiElement(Py:COMMA)(',')
PsiWhiteSpace(' ')
PyStringLiteralExpression: Name
PsiElement(Py:SINGLE_QUOTED_STRING)('u'Name'')
PsiElement(Py:RPAR)(')')
PsiElement(Py:DOT)('.')
PsiElement(Py:IDENTIFIER)('text')
PsiWhiteSpace(' ')
PsiElement(Py:EQ)('=')
PsiWhiteSpace(' ')
PyReferenceExpression: dict_name
PsiElement(Py:IDENTIFIER)('dict_name')
+2
View File
@@ -22,6 +22,8 @@ PyFile:IncompleteFor.py
PsiElement(Py:IDENTIFIER)('ba')
PsiErrorElement:colon expected
<empty list>
PyStatementList
<empty list>
PsiWhiteSpace('\n\n')
PyFunction('bar')
PsiElement(Py:DEF_KEYWORD)('def')
@@ -17,6 +17,8 @@ PyFile:IncompleteStatementList.py
PsiElement(Py:IDENTIFIER)('ba')
PsiErrorElement:colon expected
<empty list>
PyStatementList
<empty list>
PsiWhiteSpace('\n\n')
PyFunction('bar')
PsiElement(Py:DEF_KEYWORD)('def')
+3 -1
View File
@@ -28,7 +28,9 @@ PyFile:MissingParenInCall.py
<empty list>
PsiErrorElement:colon expected
<empty list>
PsiWhiteSpace('\n\n')
PsiWhiteSpace('\n\n')
PyStatementList
<empty list>
PyFunction('clean')
PsiElement(Py:DEF_KEYWORD)('def')
PsiWhiteSpace(' ')
+2
View File
@@ -74,6 +74,8 @@ PyFile:WithStatement2.py
<empty list>
PsiErrorElement:colon expected
<empty list>
PyStatementList
<empty list>
PsiElement(Py:EQ)('=')
PsiErrorElement:statement expected, found Py:EQ
<empty list>
@@ -0,0 +1,13 @@
import xml.etree.ElementTree as etree
def entries_to_xml(entries, dict_id, dict_name, closed):
dictionary = etree.Element(u'Dictionary', IDName=dict_id)
a = etree.SubElement
a(dictionary, u'Name').text = dict_name
a(dictionary, u'Closed').text = repr(closed).lower()
a(dictionary, u'Action').text = u'false'
terms = a(dictionary, u'Terms')
for i, entry in enumerate(entries):
term = a(terms, u'Term')
a(term, u'Category')
words = a(term, u'Words')
return dictionary
@@ -0,0 +1,12 @@
import xml.etree.ElementTree as etree
def entries_to_xml(entries, dict_id, dict_name, closed):
dictionary = etree.Element(u'Dictionary', IDName=dict_id)
<selection>etree.SubElement</selection>(dictionary, u'Name').text = dict_name
etree.SubElement(dictionary, u'Closed').text = repr(closed).lower()
etree.SubElement(dictionary, u'Action').text = u'false'
terms = etree.SubElement(dictionary, u'Terms')
for i, entry in enumerate(entries):
term = etree.SubElement(terms, u'Term')
etree.SubElement(term, u'Category')
words = etree.SubElement(term, u'Words')
return dictionary
@@ -274,7 +274,25 @@ public class PyTypeTest extends PyTestCase {
" self.assertIsInstance(x, int)\n" +
" expr = x\n");
}
// PY-4279
public void testFieldReassignment() {
doTest("C1",
"class C1(object):\n" +
" def m1(self):\n" +
" pass\n" +
"\n" +
"class C2(object):\n" +
" def m2(self):\n" +
" pass\n" +
"\n" +
"class Test(object):\n" +
" def __init__(self, param1):\n" +
" self.x = param1\n" +
" self.x = C1()\n" +
" expr = self.x\n");
}
public void testSOEOnRecursiveCall() {
PyExpression expr = parseExpr("def foo(x): return foo(x)\n" +
"expr = foo(1)");
@@ -469,4 +469,13 @@ public class PythonCompletionTest extends PyTestCase {
public void testCompleteBeforeSyntaxError() { // PY-3792
doTest();
}
// PY-4279
public void testFieldReassignment() {
doTest();
}
public void testSuperInit() { // PY-5066
doTest();
}
}
@@ -196,6 +196,10 @@ public class PythonLexerTest extends PyLexerTestCase {
"Py:INDENT", "Py:PASS_KEYWORD", "Py:STATEMENT_BREAK", "Py:LINE_BREAK",
"Py:END_OF_LINE_COMMENT", "Py:DEDENT", "Py:LINE_BREAK");
}
public void testIndentAtStartOfFile() { // PY-4941
doTest(" a", "Py:SPACE", "Py:INDENT", "Py:IDENTIFIER");
}
private static void doTest(String text, String... expectedTokens) {
doLexerTest(text, new PythonIndentingLexer(), expectedTokens);
@@ -305,6 +305,10 @@ public class PythonParsingTest extends ParsingTestCase {
public void testIncompleteFor() { // PY-3792
doTest();
}
public void testCallInAssignment() { // PY-5062
doTest();
}
public void doTest() {
doTest(LanguageLevel.PYTHON25);
@@ -64,6 +64,10 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase {
public void testTypeAssertions() {
doTest();
}
public void testUnresolvedImportedModule() { // PY-2075
doTest();
}
public void testImportToContainingFile() { // PY-4372
myFixture.copyFileToProject("inspections/PyUnresolvedReferencesInspection/__init__.py", "PyUnresolvedReferencesInspection/__init__.py");
@@ -69,6 +69,10 @@ public class PyIntroduceVariableTest extends PyIntroduceTestCase {
public void testOneSidedSelection() { // PY-4456
doTestCannotPerform();
}
public void testFunctionOccurrences() { // PY-5062
doTest();
}
private void doTestCannotPerform() {
boolean thrownExpectedException = false;