diff --git a/python/resources/idea/PythonApplicationInfo.xml b/python/resources/idea/PythonApplicationInfo.xml
index 46258b020048..0e64fe8e1a02 100644
--- a/python/resources/idea/PythonApplicationInfo.xml
+++ b/python/resources/idea/PythonApplicationInfo.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml
index ef8b5d162ef8..b7f929e1e6c8 100644
--- a/python/src/META-INF/python-plugin-common.xml
+++ b/python/src/META-INF/python-plugin-common.xml
@@ -3,7 +3,7 @@
- com.jetbrains.python.PyInspectionToolProvider
+ com.jetbrains.python.inspections.PythonPyInspectionToolProvider
@@ -74,7 +74,6 @@
-
diff --git a/python/src/com/jetbrains/python/PyBundle.java b/python/src/com/jetbrains/python/PyBundle.java
new file mode 100644
index 000000000000..1af25917df61
--- /dev/null
+++ b/python/src/com/jetbrains/python/PyBundle.java
@@ -0,0 +1,39 @@
+package com.jetbrains.python;
+
+import com.intellij.CommonBundle;
+import com.intellij.reference.SoftReference;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.PropertyKey;
+
+import java.lang.ref.Reference;
+import java.util.ResourceBundle;
+
+// A copy of Ruby's.
+/**
+ * Resource bundle access.
+ * Date: Nov 25, 2008 2:36:10 AM
+ */
+public class PyBundle {
+ private static Reference ourBundle;
+
+ @NonNls
+ private static final String BUNDLE = "com.jetbrains.python.PyBundle";
+
+ private PyBundle() {
+ }
+
+ public static String message(@PropertyKey(resourceBundle = BUNDLE)String key, Object... params) {
+ return CommonBundle.message(getBundle(), key, params);
+ }
+
+ // Cached loading
+ private static ResourceBundle getBundle() {
+ ResourceBundle bundle = null;
+ if (ourBundle != null) bundle = ourBundle.get();
+ if (bundle == null) {
+ bundle = ResourceBundle.getBundle(BUNDLE);
+ ourBundle = new SoftReference(bundle);
+ }
+ return bundle;
+ }
+}
diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties
new file mode 100644
index 000000000000..25ceac78cf43
--- /dev/null
+++ b/python/src/com/jetbrains/python/PyBundle.properties
@@ -0,0 +1,91 @@
+### Generic words ###
+GNAME.function=function
+GNAME.class=class
+GNAME.var=variable
+GNAME.item=item
+
+### Actions: ACT ###
+ACT.FAMILY.import=import
+
+# AddImport
+ACT.NAME.add.import=Add import
+
+
+### Quick fixes ###
+QFIX.add.parameter.self=Add parameter 'self'
+
+
+### Inspections: INSP ###
+INSP.GROUP.python=Python
+
+# PyArgumentListInspection
+INSP.NAME.incorrect.call.arguments=Incorrect call arguments
+INSP.duplicate.argument=Duplicate argument
+INSP.duplicate.star.arg=Duplicate *arg
+INSP.duplicate.doublestar.arg=Duplicate **arg
+INSP.cannot.appear.past.keyword.arg=Cannot appear past keyword arguments
+INSP.unexpected.arg=Unexpected argument
+INSP.parameter.$0.unfilled=Parameter ''{0}'' unfilled
+
+# PyMethodParametersInspection
+INSP.NAME.problematic.first.parameter=Methods having troubles with first parameter
+INSP.must.have.first.parameter=Method must have a first parameter, usually called 'self'
+INSP.probably.mistyped.self=Did not you mean 'self'?
+INSP.usually.named.self=Usually first parameter of a method is named 'self'
+
+# PyRedeclarationInspection
+INSP.NAME.redeclaration=Names redeclared without usage
+INSP.shadows.same.named.$0.above=Shadows same-named {0} above
+
+# PyUnresolvedReferencesInspection
+INSP.NAME.unresolved.refs=Unresolved references
+INSP.module.$0.not.found=Module ''{0}'' not found
+INSP.unresolved.ref.$0=Unresolved reference ''{0}''
+INSP.unresolved.ref.$0.for.class.$1=Unresolved attribute reference ''{0}'' for class ''{1}''
+
+### Annotators ###
+ANN.deleting.none=deleting None
+ANN.assign.to.none=assignment to None
+ANN.cant.assign.to.call=can't assign to function call
+ANN.cant.delete.call=can't delete function call
+ANN.cant.aug.assign.to.generator=augmented assign to generator expression not possible
+ANN.cant.aug.assign.to.tuple.or.generator=augmented assign to tuple literal or generator expression not possible
+ANN.cant.assign.to.generator=assign to generator expression not possible
+ANN.cant.assign.to.operator=can't assign to operator
+ANN.cant.assign.to.parens=can't assign to ()
+ANN.cant.assign.to.brackets=can't assign to []
+ANN.cant.aug.assign.to.list.or.comprh=augmented assign to list literal or comprehension not possible
+ANN.cant.assign.to.comprh=assign to list comprehension not possible
+ANN.cant.aug.assign.to.comprh=augmented assign to list comprehension not possible
+ANN.cant.assign.to.literal=can't assign to literal
+ANN.cant.assign.to.lambda=can't assign to lambda
+
+ANN.break.outside.loop='break' outside loop
+ANN.continue.outside.loop='continue' outside loop
+ANN.cant.continue.in.finally='continue' not supported inside 'finally' clause
+
+### parsing
+PARSE.expected.expression=expression expected
+PARSE.expected.rbracket=']' expected
+PARSE.expected.expr.or.comma.or.bracket=expected expression, ',' or ']'
+PARSE.expected.in='in' expected
+PARSE.expected.for.or.bracket=']' or 'for' expected
+PARSE.expected.comma=',' expected
+PARSE.expected.colon=':' expected
+PARSE.expected.rpar=')' expected
+PARSE.expected.lpar='(' expected
+PARSE.expected.tick='`' (backtick) expected
+PARSE.expected.name=name expected
+PARSE.expected.colon.or.rbracket=':' or ']' expected
+PARSE.expected.comma.or.rpar=',' or ')' expected
+PARSE.expected.else='else' expected
+
+PARSE.expected.func.name=function name expected
+PARSE.expected.comma.lpar.rpar=',' or '(' or ')' expected
+PARSE.expected.statement.break=Statement break expected
+PARSE.expected.@.or.def='@' or 'def' expected
+PARSE.expected.formal.param.name=formal parameter name expected
+
+
+
+
diff --git a/python/src/com/jetbrains/python/PyNames.java b/python/src/com/jetbrains/python/PyNames.java
index 1d9d1882cfd3..84887878ed54 100644
--- a/python/src/com/jetbrains/python/PyNames.java
+++ b/python/src/com/jetbrains/python/PyNames.java
@@ -10,14 +10,16 @@ import java.util.Collections;
* @author yole
*/
public class PyNames {
- @NonNls public static final String NONE = "None";
-
private PyNames() {
}
+ @NonNls public static final String NONE = "None";
+
@NonNls public static final String INIT = "__init__";
@NonNls public static final String OBJECT = "object";
+ @NonNls public static final String DOT_PY = ".py";
+
@NonNls private static Set _UnderscoredNames = new HashSet();
static {
_UnderscoredNames.add("__abs__");
diff --git a/python/src/com/jetbrains/python/actions/AddSelfQuickfix.java b/python/src/com/jetbrains/python/actions/AddSelfQuickfix.java
new file mode 100644
index 000000000000..7ccf931668e7
--- /dev/null
+++ b/python/src/com/jetbrains/python/actions/AddSelfQuickfix.java
@@ -0,0 +1,49 @@
+package com.jetbrains.python.actions;
+
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.lang.Language;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.PythonLanguage;
+import com.jetbrains.python.psi.PyElementGenerator;
+import com.jetbrains.python.psi.PyParameter;
+import com.jetbrains.python.psi.PyParameterList;
+import com.jetbrains.python.psi.PyUtil;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Insert 'self' in a method that lacks any arguments
+ * User: dcheryasov
+ * Date: Nov 19, 2008
+ */
+public class AddSelfQuickfix implements LocalQuickFix {
+ @NotNull
+ public String getName() {
+ return PyBundle.message("QFIX.add.parameter.self");
+ }
+
+ @NonNls
+ @NotNull
+ public String getFamilyName() {
+ return PyBundle.message("INSP.GROUP.python");
+ }
+
+ public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
+ PsiElement problem_elt = descriptor.getPsiElement();
+ if (problem_elt instanceof PyParameterList) {
+ final PyParameterList param_list = (PyParameterList)problem_elt;
+ PyUtil.ensureWritable(problem_elt);
+ Language language = problem_elt.getLanguage();
+ if (language instanceof PythonLanguage) {
+ final PythonLanguage pythonLanguage = (PythonLanguage)language;
+ PyElementGenerator generator = pythonLanguage.getElementGenerator();
+ // TODO: generalize, move to generator
+ PyParameter new_param = generator.createFromText(project, PyParameter.class, "def f(self): pass", new int[]{0, 3, 1});
+ param_list.addParameter(new_param);
+ }
+ }
+ }
+}
diff --git a/python/src/com/jetbrains/python/inspections/PyMethodParametersInspection.java b/python/src/com/jetbrains/python/inspections/PyMethodParametersInspection.java
index 086dfc197761..383ccb15314e 100644
--- a/python/src/com/jetbrains/python/inspections/PyMethodParametersInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyMethodParametersInspection.java
@@ -1,14 +1,17 @@
package com.jetbrains.python.inspections;
-import com.intellij.codeInspection.LocalInspectionTool;
-import com.intellij.codeInspection.ProblemsHolder;
-import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
-import com.intellij.psi.PsiElementVisitor;
-import com.intellij.psi.PsiElement;
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.codeInspection.ProblemHighlightType;
+import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.jetbrains.python.PyBundle;
+import com.jetbrains.python.actions.AddSelfQuickfix;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
@@ -20,13 +23,13 @@ public class PyMethodParametersInspection extends LocalInspectionTool {
@Nls
@NotNull
public String getGroupDisplayName() {
- return "Python"; // TODO: propertize
+ return PyBundle.message("INSP.GROUP.python");
}
@Nls
@NotNull
public String getDisplayName() {
- return "Method lacking first parameter"; // TODO: propertize
+ return PyBundle.message("INSP.NAME.problematic.first.parameter");
}
@NotNull
@@ -66,22 +69,32 @@ public class PyMethodParametersInspection extends LocalInspectionTool {
// TODO: check for "staticmetod"
ASTNode name_node = node.getNameNode();
if (name_node != null) {
- registerProblem(name_node.getPsi(), "Method must have a first parameter, usually called 'self'", ProblemHighlightType.ERROR, null);
+ PsiElement open_paren = plist.getFirstChild();
+ PsiElement close_paren = plist.getLastChild();
+ if (
+ open_paren != null && close_paren != null &&
+ "(".equals(open_paren.getText()) && ")".equals(close_paren.getText())
+ ) {
+ registerProblem(
+ plist, PyBundle.message("INSP.must.have.first.parameter"),
+ ProblemHighlightType.GENERIC_ERROR, null, new AddSelfQuickfix()
+ );
+ }
}
}
else {
String pname = params[0].getText();
- // TODO: generate a better list, or use Levenstein's distance, etc.
- for (String typo : new String[] {"elf", "sef", "sel", "slf", "sself", "seelf", "sellf"}) {
+ // every dup, swap, drop, or dup+drop of "self"
+ @NonNls String[] mangled = {"eslf", "sself", "elf", "felf", "slef", "seelf", "slf", "sslf", "sefl", "sellf", "sef", "seef"};
+ for (String typo : mangled) {
if (typo.equals(pname)) {
- registerProblem(params[0].getNode().getPsi(), "Did not you mean 'self'?");
- // NOTE: test framework rejects weak warnings, which would be more appropriate
+ registerProblem(params[0].getNode().getPsi(), PyBundle.message("INSP.probably.mistyped.self"));
return;
}
}
// TODO: check for "classmethod" or "staticmetod" and style settings
if (!"self".equals(pname)) {
- registerProblem(plist, "Usually first parameter of a method is named 'self'");
+ registerProblem(plist, PyBundle.message("INSP.usually.named.self"));
}
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java b/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java
index d8ed4533a12a..6668fd17c838 100644
--- a/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java
@@ -6,6 +6,7 @@ import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.jetbrains.python.PyTokenTypes;
+import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -20,13 +21,13 @@ public class PyRedeclarationInspection extends LocalInspectionTool {
@Nls
@NotNull
public String getGroupDisplayName() {
- return "Python"; // TODO: propertize
+ return PyBundle.message("INSP.GROUP.python");
}
@Nls
@NotNull
public String getDisplayName() {
- return "Duplicate definition"; // TODO: propertize
+ return PyBundle.message("INSP.NAME.redeclaration");
}
@NotNull
@@ -58,21 +59,24 @@ public class PyRedeclarationInspection extends LocalInspectionTool {
// TODO: This function is a shame; replace with a proper interface.
private static String _getKind(PsiElement elt) {
- if (elt instanceof PyFunction) return "function";
- if (elt instanceof PyClass) return "class";
- if (elt instanceof PyTargetExpression) return "variable";
- return "item";
+ if (elt instanceof PyFunction) return PyBundle.message("GNAME.function");
+ if (elt instanceof PyClass) return PyBundle.message("GNAME.class");
+ if (elt instanceof PyTargetExpression) return PyBundle.message("GNAME.var");
+ return PyBundle.message("GNAME.item");
}
- private void _checkAbove(PyElement node, String kind) {
+ private void _checkAbove(PyElement node, String kind) {
String name = node.getName();
if (name != null) {
PyResolveUtil.ResolveProcessor proc = new PyResolveUtil.ResolveProcessor(node.getName());
PyResolveUtil.treeCrawlUp(proc, node);
PsiElement found = proc.getResult();
// TODO: check if the redefined name is used somehow
- if (found != null) {
- registerProblem(node.getNode().findChildByType(PyTokenTypes.IDENTIFIER).getPsi(), "Shadows same-named " + _getKind(found) + " above");
+ if (found != null && ! (found instanceof PyTargetExpression)) {
+ registerProblem(
+ node.getNode().findChildByType(PyTokenTypes.IDENTIFIER).getPsi(),
+ PyBundle.message("INSP.shadows.same.named.$0.above", _getKind(found))
+ );
//registerProblem(prev.getNode().findChildByType(PyTokenTypes.IDENTIFIER).getPsi(), "Overridden by same-named " + kind + " below");
}
}
@@ -82,17 +86,17 @@ public class PyRedeclarationInspection extends LocalInspectionTool {
@Override
public void visitPyFunction(final PyFunction node) {
- _checkAbove(node, "function");
+ _checkAbove(node, PyBundle.message("GNAME.function"));
}
@Override
public void visitPyTargetExpression(final PyTargetExpression node) {
- _checkAbove(node, "variable");
+ _checkAbove(node, PyBundle.message("GNAME.var"));
}
@Override
public void visitPyClass(final PyClass node) {
- _checkAbove(node, "class");
+ _checkAbove(node, PyBundle.message("GNAME.class"));
}
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java
index ec206d64aa93..a5bb022b7073 100644
--- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java
@@ -1,20 +1,22 @@
package com.jetbrains.python.inspections;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
+import com.intellij.codeInspection.HintAction;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.lang.annotation.HighlightSeverity;
+import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiReference;
import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyModuleType;
import com.jetbrains.python.psi.types.PyNoneType;
import com.jetbrains.python.psi.types.PyType;
-import com.jetbrains.python.validation.AddImportAction;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -27,13 +29,13 @@ public class PyUnresolvedReferencesInspection extends LocalInspectionTool {
@Nls
@NotNull
public String getGroupDisplayName() {
- return "Python"; // TODO: propertize
+ return PyBundle.message("INSP.GROUP.python");
}
@Nls
@NotNull
public String getDisplayName() {
- return "Unresolved Python reference"; // TODO: propertize
+ return PyBundle.message("INSP.NAME.unresolved.refs");
}
@NotNull
@@ -76,6 +78,9 @@ public class PyUnresolvedReferencesInspection extends LocalInspectionTool {
if (reference.resolve() == null) {
StringBuffer description_buf = new StringBuffer("");
String text = reference.getElement().getText();
+ String ref_text = reference.getRangeInElement().substring(text); // text of the part we're working with
+ HintAction action = null;
+ if (ref_text.length() <= 0) return; // empty text, nothing to highlight
if (reference instanceof PyReferenceExpression) {
PyReferenceExpression refex = (PyReferenceExpression)reference;
String refname = refex.getReferencedName();
@@ -90,8 +95,9 @@ public class PyUnresolvedReferencesInspection extends LocalInspectionTool {
if ((PsiTreeUtil.getParentOfType(
PsiTreeUtil.getParentOfType(node, PyImportElement.class), PyTryExceptStatement.class, PyIfStatement.class) != null)
) {
- severity = HighlightSeverity.WARNING;
- description_buf.append("Module '").append(reference.getRangeInElement().substring(text)).append("' not found");
+ severity = HighlightSeverity.INFO;
+ String errmsg = PyBundle.message("INSP.module.$0.not.found", ref_text);
+ description_buf.append(errmsg);
}
}
if (reference instanceof PsiReferenceEx) {
@@ -99,7 +105,7 @@ public class PyUnresolvedReferencesInspection extends LocalInspectionTool {
if (s != null) description_buf.append(s);
}
if (description_buf.length() == 0) {
- description_buf.append("Unresolved reference '").append(reference.getRangeInElement().substring(text)).append("'");
+ boolean marked_for_class = false;
if (reference instanceof PyQualifiedExpression) {
final PyExpression qexpr = ((PyQualifiedExpression)reference).getQualifier();
if (qexpr != null) {
@@ -109,24 +115,27 @@ public class PyUnresolvedReferencesInspection extends LocalInspectionTool {
// this almost always means that we don't know the type, so don't show an error in this case
continue;
}
- description_buf.append(" for class ").append(qtype.getName());
+ description_buf.append(PyBundle.message("INSP.unresolved.ref.$0.for.class.$1", ref_text, qtype.getName()));
+ marked_for_class = true;
}
}
}
+ if (! marked_for_class) {
+ description_buf.append(PyBundle.message("INSP.unresolved.ref.$0", ref_text));
+ /*action = new AddImportAction(reference);*/
+ }
}
String description = description_buf.toString();
ProblemHighlightType hl_type;
- //final TextRange highlightRange = reference.getRangeInElement().shiftRight(reference.getElement().getTextRange().getStartOffset());
if (severity == HighlightSeverity.WARNING) {
- //annotation = getHolder().createWarningAnnotation(highlightRange, description_buf.toString());
hl_type = ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
}
else {
- //annotation = getHolder().createErrorAnnotation(highlightRange, description_buf.toString());
- //annotation.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
hl_type = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL;
}
- registerProblem(reference.getElement(), description, hl_type, new AddImportAction(reference));
+ PsiElement point = node.getLastChild(); // usually the identifier at the end of qual ref
+ if (point == null) point = node;
+ registerProblem(/*reference.getElement()*/ point, description, hl_type, action);
}
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PythonPyInspectionToolProvider.java b/python/src/com/jetbrains/python/inspections/PythonPyInspectionToolProvider.java
new file mode 100644
index 000000000000..66d6546243ec
--- /dev/null
+++ b/python/src/com/jetbrains/python/inspections/PythonPyInspectionToolProvider.java
@@ -0,0 +1,68 @@
+package com.jetbrains.python.inspections;
+
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.codeInspection.ex.InspectionTool;
+import com.intellij.codeInspection.ex.InspectionToolRegistrar;
+import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.util.Factory;
+import com.jetbrains.python.JythonManager;
+import org.jetbrains.annotations.NotNull;
+import org.python.core.PyList;
+import org.python.core.PyObject;
+
+/**
+ * @author yole
+ */
+public class PythonPyInspectionToolProvider implements ApplicationComponent {
+ public static PythonPyInspectionToolProvider getInstance() {
+ return ApplicationManager.getApplication().getComponent(PythonPyInspectionToolProvider.class);
+ }
+
+ private InspectionToolRegistrar myRegistrar;
+
+ public PythonPyInspectionToolProvider(final InspectionToolRegistrar registrar) {
+ myRegistrar = registrar;
+ }
+
+ @NotNull
+ public String getComponentName() {
+ return "PythonPyInspectionToolProvider";
+ }
+
+ public void initComponent() {
+ JythonManager manager = JythonManager.getInstance();
+ manager.execScriptFromResource("inspections/inspections.py");
+
+ final PyList pyList = (PyList) manager.eval("getAllInspections()");
+ int len = pyList.__len__();
+ for(int i=0; i {
+ private String myInspectionToolName;
+
+ public PyInspectionToolFactory(final String inspectionToolName) {
+ myInspectionToolName = inspectionToolName;
+ }
+
+ public InspectionTool create() {
+ final LocalInspectionTool tool = createLocalInspectionTool(myInspectionToolName);
+ return new LocalInspectionToolWrapper(tool);
+ }
+ }
+}
diff --git a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
index 7275e08f92b3..0c60f8be21f6 100644
--- a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
+++ b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
@@ -19,6 +19,7 @@ package com.jetbrains.python.parsing;
import com.intellij.lang.PsiBuilder;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.tree.IElementType;
+import static com.jetbrains.python.PyBundle.message;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyTokenTypes;
@@ -96,7 +97,7 @@ public class ExpressionParsing extends Parsing {
return;
}
if (!parseSingleExpression(isTargetExpression)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
if (builder.getTokenType() == PyTokenTypes.FOR_KEYWORD) {
parseListCompExpression(expr, PyTokenTypes.RBRACKET, PyElementTypes.LIST_COMP_EXPRESSION);
@@ -107,11 +108,11 @@ public class ExpressionParsing extends Parsing {
builder.advanceLexer();
}
else if (!parseSingleExpression(isTargetExpression)) {
- builder.error("expression or , or ] expected");
+ builder.error(message("PARSE.expected.expr.or.comma.or.bracket"));
break;
}
}
- checkMatches(PyTokenTypes.RBRACKET, "] expected");
+ checkMatches(PyTokenTypes.RBRACKET, message("PARSE.expected.rbracket"));
expr.done(PyElementTypes.LIST_LITERAL_EXPRESSION);
}
}
@@ -123,9 +124,9 @@ public class ExpressionParsing extends Parsing {
while (true) {
myBuilder.advanceLexer();
parseExpression(true, true);
- checkMatches(PyTokenTypes.IN_KEYWORD, "'in' expected");
+ checkMatches(PyTokenTypes.IN_KEYWORD, message("PARSE.expected.in"));
if (!parseTupleExpression(false, false, true)) {
- myBuilder.error("expression expected");
+ myBuilder.error(message("PARSE.expected.expression"));
}
while (myBuilder.getTokenType() == PyTokenTypes.IF_KEYWORD) {
myBuilder.advanceLexer();
@@ -140,7 +141,7 @@ public class ExpressionParsing extends Parsing {
expr = expr.precede();
continue;
}
- myBuilder.error("closing bracket or 'for' expected");
+ myBuilder.error(message("PARSE.expected.for.or.bracket"));
break;
}
expr.done(exprType);
@@ -155,7 +156,7 @@ public class ExpressionParsing extends Parsing {
break;
}
if (builder.getTokenType() != PyTokenTypes.RBRACE) {
- checkMatches(PyTokenTypes.COMMA, "comma expected");
+ checkMatches(PyTokenTypes.COMMA, message("PARSE.expected.comma"));
}
}
builder.advanceLexer();
@@ -168,7 +169,7 @@ public class ExpressionParsing extends Parsing {
marker.drop();
return false;
}
- checkMatches(PyTokenTypes.COLON, ": expected");
+ checkMatches(PyTokenTypes.COLON, message("PARSE.expected.colon"));
if (!parseSingleExpression(false)) {
marker.drop();
return false;
@@ -191,7 +192,7 @@ public class ExpressionParsing extends Parsing {
parseListCompExpression(expr, PyTokenTypes.RPAR, PyElementTypes.GENERATOR_EXPRESSION);
}
else {
- checkMatches(PyTokenTypes.RPAR, ") expected");
+ checkMatches(PyTokenTypes.RPAR, message("PARSE.expected.rpar"));
expr.done(PyElementTypes.PARENTHESIZED_EXPRESSION);
}
}
@@ -202,7 +203,7 @@ public class ExpressionParsing extends Parsing {
final PsiBuilder.Marker expr = builder.mark();
builder.advanceLexer();
parseExpression();
- checkMatches(PyTokenTypes.TICK, "` expected");
+ checkMatches(PyTokenTypes.TICK, message("PARSE.expected.tick"));
expr.done(PyElementTypes.REPR_EXPRESSION);
}
@@ -227,7 +228,7 @@ public class ExpressionParsing extends Parsing {
}
else recast_first_identifier = false;
builder.advanceLexer();
- checkMatches(PyTokenTypes.IDENTIFIER, "name expected");
+ checkMatches(PyTokenTypes.IDENTIFIER, message("PARSE.expected.name"));
if (isTargetExpression && builder.getTokenType() != PyTokenTypes.DOT) {
expr.done(PyElementTypes.TARGET_EXPRESSION);
}
@@ -254,7 +255,7 @@ public class ExpressionParsing extends Parsing {
parseSliceEnd(builder, expr);
}
else {
- checkMatches(PyTokenTypes.RBRACKET, "] expected");
+ checkMatches(PyTokenTypes.RBRACKET, message("PARSE.expected.rbracket"));
expr.done(PyElementTypes.SUBSCRIPTION_EXPRESSION);
}
}
@@ -287,13 +288,13 @@ public class ExpressionParsing extends Parsing {
parseExpression();
}
if (builder.getTokenType() != PyTokenTypes.RBRACKET && builder.getTokenType() != PyTokenTypes.COLON) {
- builder.error(": or ] expected");
+ builder.error(message("PARSE.expected.colon.or.rbracket"));
}
if (builder.getTokenType() == PyTokenTypes.COLON) {
builder.advanceLexer();
parseExpressionOptional();
}
- checkMatches(PyTokenTypes.RBRACKET, "] expected");
+ checkMatches(PyTokenTypes.RBRACKET, message("PARSE.expected.rbracket"));
}
expr.done(PyElementTypes.SLICE_EXPRESSION);
}
@@ -320,7 +321,7 @@ public class ExpressionParsing extends Parsing {
}
}
else {
- builder.error(", or ) expected");
+ builder.error(message("PARSE.expected.comma.or.rpar"));
break;
}
}
@@ -328,7 +329,7 @@ public class ExpressionParsing extends Parsing {
final PsiBuilder.Marker starArgMarker = builder.mark();
builder.advanceLexer();
if (!parseSingleExpression(false)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
starArgMarker.done(PyElementTypes.STAR_ARGUMENT_EXPRESSION);
}
@@ -339,7 +340,7 @@ public class ExpressionParsing extends Parsing {
if (builder.getTokenType() == PyTokenTypes.EQ) {
builder.advanceLexer();
if (!parseSingleExpression(false)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
keywordArgMarker.done(PyElementTypes.KEYWORD_ARGUMENT_EXPRESSION);
continue;
@@ -347,14 +348,14 @@ public class ExpressionParsing extends Parsing {
keywordArgMarker.rollbackTo();
}
if (!parseSingleExpression(false)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
}
}
if (needBracket) {
genexpr.drop();
- checkMatches(PyTokenTypes.RPAR, ") expected");
+ checkMatches(PyTokenTypes.RPAR, message("PARSE.expected.rpar"));
}
arglist.done(PyElementTypes.ARGUMENT_LIST);
}
@@ -369,13 +370,13 @@ public class ExpressionParsing extends Parsing {
public void parseExpression() {
if (!parseExpressionOptional()) {
- myBuilder.error("expression expected");
+ myBuilder.error(message("PARSE.expected.expression"));
}
}
public void parseExpression(boolean stopOnIn, boolean isTargetExpression) {
if (!parseTupleExpression(stopOnIn, isTargetExpression, false)) {
- myBuilder.error("expression expected");
+ myBuilder.error(message("PARSE.expected.expression"));
}
}
@@ -434,16 +435,16 @@ public class ExpressionParsing extends Parsing {
if (myBuilder.getTokenType() == PyTokenTypes.IF_KEYWORD) {
myBuilder.advanceLexer();
if (!parseORTestExpression(myBuilder, stopOnIn, isTargetExpression)) {
- myBuilder.error("expression expected");
+ myBuilder.error(message("PARSE.expected.expression"));
}
else {
if (myBuilder.getTokenType() != PyTokenTypes.ELSE_KEYWORD) {
- myBuilder.error("'else' expected");
+ myBuilder.error(message("PARSE.expected.else"));
}
else {
myBuilder.advanceLexer();
if (!parseTestExpression(stopOnIn, isTargetExpression)) {
- myBuilder.error("expression expected");
+ myBuilder.error(message("PARSE.expected.expression"));
}
}
}
@@ -468,7 +469,7 @@ public class ExpressionParsing extends Parsing {
getFunctionParser().parseParameterListContents(PyTokenTypes.COLON, false);
boolean parseExpressionResult = oldTest ? parseOldTestExpression() : parseSingleExpression(false);
if (!parseExpressionResult) {
- myBuilder.error("expression expected");
+ myBuilder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.LAMBDA_EXPRESSION);
return true;
@@ -483,7 +484,7 @@ public class ExpressionParsing extends Parsing {
while (builder.getTokenType() == PyTokenTypes.OR_KEYWORD) {
builder.advanceLexer();
if (!parseANDTestExpression(builder, stopOnIn, isTargetExpression)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
@@ -502,7 +503,7 @@ public class ExpressionParsing extends Parsing {
while (builder.getTokenType() == PyTokenTypes.AND_KEYWORD) {
builder.advanceLexer();
if (!parseNOTTestExpression(builder, stopOnIn, isTargetExpression)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
@@ -517,7 +518,7 @@ public class ExpressionParsing extends Parsing {
final PsiBuilder.Marker expr = builder.mark();
builder.advanceLexer();
if (!parseNOTTestExpression(builder, stopOnIn, isTargetExpression)) {
- builder.error("Expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.PREFIX_EXPRESSION);
return true;
@@ -559,7 +560,7 @@ public class ExpressionParsing extends Parsing {
}
if (!parseBitwiseORExpression(builder, isTargetExpression)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
@@ -578,7 +579,7 @@ public class ExpressionParsing extends Parsing {
while (builder.getTokenType() == PyTokenTypes.OR) {
builder.advanceLexer();
if (!parseBitwiseXORExpression(builder, isTargetExpression)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
@@ -597,7 +598,7 @@ public class ExpressionParsing extends Parsing {
while (builder.getTokenType() == PyTokenTypes.XOR) {
builder.advanceLexer();
if (!parseBitwiseANDExpression(builder, isTargetExpression)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
@@ -616,7 +617,7 @@ public class ExpressionParsing extends Parsing {
while (builder.getTokenType() == PyTokenTypes.AND) {
builder.advanceLexer();
if (!parseShiftExpression(builder, isTargetExpression)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
@@ -635,7 +636,7 @@ public class ExpressionParsing extends Parsing {
while (PyTokenTypes.SHIFT_OPERATIONS.contains(builder.getTokenType())) {
builder.advanceLexer();
if (!parseAdditiveExpression(builder, isTargetExpression)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
@@ -654,7 +655,7 @@ public class ExpressionParsing extends Parsing {
while (PyTokenTypes.ADDITIVE_OPERATIONS.contains(builder.getTokenType())) {
builder.advanceLexer();
if (!parseMultiplicativeExpression(builder, isTargetExpression)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
@@ -674,7 +675,7 @@ public class ExpressionParsing extends Parsing {
while (PyTokenTypes.MULTIPLICATIVE_OPERATIONS.contains(builder.getTokenType())) {
builder.advanceLexer();
if (!parseUnaryExpression(builder, isTargetExpression)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.BINARY_EXPRESSION);
expr = expr.precede();
@@ -690,7 +691,7 @@ public class ExpressionParsing extends Parsing {
final PsiBuilder.Marker expr = builder.mark();
builder.advanceLexer();
if (!parseUnaryExpression(builder, isTargetExpression)) {
- builder.error("Expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.PREFIX_EXPRESSION);
return true;
@@ -710,7 +711,7 @@ public class ExpressionParsing extends Parsing {
if (builder.getTokenType() == PyTokenTypes.EXP) {
builder.advanceLexer();
if (!parseUnaryExpression(builder, isTargetExpression)) {
- builder.error("expression expected");
+ builder.error(message("PARSE.expected.expression"));
}
expr.done(PyElementTypes.BINARY_EXPRESSION);
}
diff --git a/python/src/com/jetbrains/python/psi/PyElementGenerator.java b/python/src/com/jetbrains/python/psi/PyElementGenerator.java
index eaafef72951c..6c84e1229011 100644
--- a/python/src/com/jetbrains/python/psi/PyElementGenerator.java
+++ b/python/src/com/jetbrains/python/psi/PyElementGenerator.java
@@ -62,4 +62,6 @@ public interface PyElementGenerator {
void setStringValue(PyStringLiteralExpression string, String value);
PyImportStatement createImportStatementFromText(Project project, String text);
+
+ T createFromText(final Project project, Class aClass, final String text, final int[] path);
}
diff --git a/python/src/com/jetbrains/python/psi/PyExpression.java b/python/src/com/jetbrains/python/psi/PyExpression.java
index d3751f97989f..0bbaca0a7c1e 100644
--- a/python/src/com/jetbrains/python/psi/PyExpression.java
+++ b/python/src/com/jetbrains/python/psi/PyExpression.java
@@ -20,6 +20,7 @@ import com.jetbrains.python.psi.types.PyType;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -29,7 +30,7 @@ import java.util.List;
*/
public interface PyExpression extends PyElement {
PyExpression[] EMPTY_ARRAY = new PyExpression[0];
- List EMPTY_LIST = new ArrayList(0);
+ List EMPTY_LIST = Collections.unmodifiableList(new ArrayList(0));
@Nullable
PyType getType();
diff --git a/python/src/com/jetbrains/python/psi/PyParameterList.java b/python/src/com/jetbrains/python/psi/PyParameterList.java
index 134908a4d902..5d432ca566b3 100644
--- a/python/src/com/jetbrains/python/psi/PyParameterList.java
+++ b/python/src/com/jetbrains/python/psi/PyParameterList.java
@@ -28,4 +28,10 @@ import com.jetbrains.python.psi.stubs.PyParameterListStub;
*/
public interface PyParameterList extends PyElement, StubBasedPsiElement, NameDefiner {
PyParameter[] getParameters();
+
+ /**
+ * Adds a paramter to list, after all other parameters.
+ * @param param
+ */
+ void addParameter(PyParameter param);
}
diff --git a/python/src/com/jetbrains/python/psi/impl/EvaluatedTextRange.java b/python/src/com/jetbrains/python/psi/impl/EvaluatedTextRange.java
index 143ea691b84a..202a435555d8 100644
--- a/python/src/com/jetbrains/python/psi/impl/EvaluatedTextRange.java
+++ b/python/src/com/jetbrains/python/psi/impl/EvaluatedTextRange.java
@@ -17,6 +17,7 @@
package com.jetbrains.python.psi.impl;
import com.intellij.openapi.util.TextRange;
+import org.jetbrains.annotations.NonNls;
public class EvaluatedTextRange {
private TextRange range;
@@ -39,7 +40,7 @@ public class EvaluatedTextRange {
return value;
}
-
+ @NonNls
public String toString() {
return "EvaluatedTextRange[" + range + "]: " + value;
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java
index 57ffe3ee241b..196acb2df4e1 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java
@@ -239,4 +239,14 @@ public class PyElementGeneratorImpl implements PyElementGenerator {
final PsiFile dummyFile = createDummyFile(project, text);
return (PyImportStatement)dummyFile.getFirstChild();
}
+
+ public T createFromText(final Project project, Class aClass, final String text, final int[] path) {
+ final PsiFile dummyFile = createDummyFile(project, text);
+ PsiElement ret = dummyFile;
+ for (int skip : path) {
+ ret = ret.getFirstChild();
+ for (int i = 0; i < skip; i += 1) ret = ret.getNextSibling();
+ }
+ return (T)ret;
+ }
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyParameterListImpl.java b/python/src/com/jetbrains/python/psi/impl/PyParameterListImpl.java
index 439c5e6b5871..8fd3e0f8d925 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyParameterListImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyParameterListImpl.java
@@ -17,6 +17,7 @@
package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.stubs.PyParameterListStub;
@@ -47,6 +48,30 @@ public class PyParameterListImpl extends PyBaseElementImpl
return getStubOrPsiChildren(PyElementTypes.FORMAL_PARAMETER, new PyParameter[0]);
}
+ public void addParameter(final PyParameter param) {
+ PsiElement paren = getLastChild();
+ if (paren != null && ")".equals(paren.getText())) {
+ PyUtil.ensureWritable(this);
+ ASTNode beforeWhat = paren.getNode(); // the closing bracket will be this
+ PyParameter[] params = getParameters();
+ addItemNode(param, beforeWhat, true, params.length == 0);
+ }
+ }
+
+ // TODO: open for general usage by all list-like structurtes
+ private void addItemNode(PyParameter item, ASTNode beforeThis, boolean isFirst, boolean isLast) {
+ PyUtil.ensureWritable(this);
+ ASTNode node = getNode();
+ ASTNode itemNode = item.getNode();
+ if (! isFirst) {
+ node.addChild(getLanguage().getElementGenerator().createComma(getProject()), beforeThis);
+ }
+ node.addChild(itemNode, beforeThis);
+ if (! isLast) {
+ node.addChild(getLanguage().getElementGenerator().createComma(getProject()), beforeThis);
+ }
+ }
+
@NotNull
public Iterable iterateNames() {
return new ArrayIterable(getParameters());
diff --git a/python/src/com/jetbrains/python/validation/AddImportAction.java b/python/src/com/jetbrains/python/validation/AddImportAction.java
index 5ba44e2ba7d8..1a5e79d72e9a 100644
--- a/python/src/com/jetbrains/python/validation/AddImportAction.java
+++ b/python/src/com/jetbrains/python/validation/AddImportAction.java
@@ -8,6 +8,8 @@ import com.intellij.codeInsight.daemon.impl.ShowAutoImportPass;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.hint.QuestionAction;
import com.intellij.codeInspection.HintAction;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
@@ -17,13 +19,15 @@ import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
+import com.jetbrains.python.PyBundle;
+import static com.jetbrains.python.PyNames.DOT_PY;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.ResolveImportUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-public class AddImportAction implements HintAction, QuestionAction {
+public class AddImportAction implements HintAction, QuestionAction, LocalQuickFix {
private final PsiReference myReference;
private Project myProject;
private static final Logger LOG = Logger.getInstance("#" + AddImportAction.class.getName());
@@ -35,7 +39,7 @@ public class AddImportAction implements HintAction, QuestionAction {
@NotNull
public String getText() {
- return "Add import";
+ return PyBundle.message("ACT.NAME.add.import");
}
@NotNull
@@ -45,7 +49,11 @@ public class AddImportAction implements HintAction, QuestionAction {
@NotNull
public String getFamilyName() {
- return "import";
+ return PyBundle.message("ACT.FAMILY.import");
+ }
+
+ public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
+ execute(descriptor.getPsiElement().getContainingFile());
}
@Nullable
@@ -54,7 +62,7 @@ public class AddImportAction implements HintAction, QuestionAction {
}
protected PsiFile[] getRefFiles(final String referenceName) {
- PsiFile[] files = FilenameIndex.getFilesByName(myProject, referenceName + ".py", GlobalSearchScope.allScope(myProject));
+ PsiFile[] files = FilenameIndex.getFilesByName(myProject, referenceName + DOT_PY, GlobalSearchScope.allScope(myProject));
if (files == null) files = PsiFile.EMPTY_ARRAY;
return files;
}
diff --git a/python/src/com/jetbrains/python/validation/BreakContinueAnnotator.java b/python/src/com/jetbrains/python/validation/BreakContinueAnnotator.java
index ab82eb067fe9..222188ce7da7 100644
--- a/python/src/com/jetbrains/python/validation/BreakContinueAnnotator.java
+++ b/python/src/com/jetbrains/python/validation/BreakContinueAnnotator.java
@@ -17,10 +17,11 @@
package com.jetbrains.python.validation;
import com.intellij.psi.PsiElement;
+import static com.jetbrains.python.PyBundle.message;
+import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.psi.PyBreakStatement;
import com.jetbrains.python.psi.PyContinueStatement;
import com.jetbrains.python.psi.PyTryExceptStatement;
-import com.jetbrains.python.PyElementTypes;
/**
* Created by IntelliJ IDEA.
@@ -32,13 +33,13 @@ import com.jetbrains.python.PyElementTypes;
public class BreakContinueAnnotator extends PyAnnotator {
@Override public void visitPyBreakStatement(final PyBreakStatement node) {
if (node.getContainingElement(PyElementTypes.LOOPS) == null) {
- getHolder().createErrorAnnotation(node, "'break' outside of loop");
+ getHolder().createErrorAnnotation(node, message("ANN.break.outside.loop"));
}
}
@Override public void visitPyContinueStatement(final PyContinueStatement node) {
if (node.getContainingElement(PyElementTypes.LOOPS) == null) {
- getHolder().createErrorAnnotation(node, "'continue' outside of loop");
+ getHolder().createErrorAnnotation(node, message("ANN.continue.outside.loop"));
return;
}
PyTryExceptStatement tryStatement = node.getContainingElement(PyTryExceptStatement.class);
@@ -46,7 +47,7 @@ public class BreakContinueAnnotator extends PyAnnotator {
PsiElement parent = node.getParent();
while (parent != null) {
if (parent == tryStatement.getFinallyStatementList()) {
- getHolder().createErrorAnnotation(node, "'continue' not supported inside 'finally' clause");
+ getHolder().createErrorAnnotation(node, message("ANN.cant.continue.in.finally"));
break;
}
parent = parent.getParent();
diff --git a/python/src/com/jetbrains/python/validation/PythonReferenceImporter.java b/python/src/com/jetbrains/python/validation/PythonReferenceImporter.java
index 968ba6478de9..48a9a0169209 100644
--- a/python/src/com/jetbrains/python/validation/PythonReferenceImporter.java
+++ b/python/src/com/jetbrains/python/validation/PythonReferenceImporter.java
@@ -17,6 +17,10 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
public class PythonReferenceImporter implements ReferenceImporter {
+ public PythonReferenceImporter() {
+ // nothing
+ }
+
public boolean autoImportReferenceAtCursor(@NotNull final Editor editor, @NotNull final PsiFile file) {
int caretOffset = editor.getCaretModel().getOffset();
Document document = editor.getDocument();