Snapshot dc1944e804515a346297e368c3b9c35a203c9912 from idea/133.818 of git://git.jetbrains.org/idea/community.git
dc1944e: Merge remote-tracking branch 'origin/133' into 133
c2e9002: Merge remote-tracking branch 'origin/133' into 133
dbd4198: IDEA-117777 Change the way native splashscreen is shown in WinLauncher IDEA-117163 Parameter "nosplash" is broken on launcher (cherry picked from commit b783716)
cfcbcbb: distinct prover: do not distinguish raw type arguments from type arguments without params (IDEA-119546) (cherry picked from commit baee0eb)
a1b2686: Copyright: commit document after comment updating (cherry picked from commit 0f2e2a5)
210e309: IDEA-119677 AWT thread blocking during start up
607d561: do not replace checked exception with unchecked (IDEA-119345)
34d7d0d: cls reference ignores passed outer class type arguments (IDEA-118733)
afb6d22: revert (IDEA-120153)
512ceae: temp solution (IDEA-118527) (cherry picked from commit 32094bf)
a1cb63e: Merge remote-tracking branch 'origin/133' into 133
b90c09e: Logo updated: 'Tools matter' moved.
87174f2: [git] Don't read default commit message from .COMMIT_EDITMSG
00bc294: Add new plugins to brokenPlugins.txt
a42d688: PyCharm 3.1 artwork
c7a0fea: IDEA-119510 Update Pivotal connector to correctly set "Started" and "Finished" states for stories. Unify titles of error dialogs in "Close task" and "Open task" actions. (cherry picked from commit 85bcbe8)
c498973: root detection call optimized for empty root checkers (cherry picked from commit acdc335)
f54d2a5: unnecessary 'else' removed (cherry picked from commit 65bce6c)
2f60cdc: style (cherry picked from commit 321cebb)
0ca33de: VcsRootDetectorI renamed (cherry picked from commit 5a75778)
e8a0a07: VcsRootDetector refactoring
dd9ee0b: GitRootFinder removed as unnecessary (cherry picked from commit 470ad4d)
6061019: IDEA-119738 Problem with Android Studio connecting to wrong VCS (Git vs. Mercurial)
a0afcc5: style (cherry picked from commit 1195dd4)
0b6023f: Mercurial Repository info problem fixed
eae61e9: style (cherry picked from commit 96ec395)
6be71da: Unnecessary parameter --ignore removed from appropriate status commands.
8d896ca: Annotate for renamed/moved file fixed
95fe78f: getFileNameInTargetRevision updated
2eb0039: VcsRoot detector tests updated
5a89ec5: VcsRootError changed to be an interface, implementation moved to vcs-impl (cherry picked from commit 49815e2)
6e7297f: Reverted percent formatting by default for MySQL parser compatibility with Python (PY-10771)
c92b0d9: Fixed add method quick fix after changing the element reported by the unresolved references inspection
cede286: do not prefer simple python run configuration over tests
fa2e308: do not prefer simple python run configuration over custom (django, etc.)
5bdf739: Don't use JSON to store broken plugins. Loading JSON on startup take 50m.s.
e2617c0: Fill brokenPlugins.json (cherry picked from commit ebf4294)
50938aa: [git] IDEA-120042 Protect against zero timestamp
03b587d: Kill Python console with SIGKILL, because SIGINT generates KeyboardInterrupt and closes nothing. (cherry picked from commit 35603ff416a1c6b95d2ba4459fcc7bbb864315a1)
24baeea: NotNull annotation. (cherry picked from commit 8bf273fc402c574fe67f39f0a43018e0b3758cdd)
4fb7ecf: NotNull annotation. (cherry picked from commit 8204f64b865634da512600488441c5001e902c5d)
13a9206: NPE (EA-52843) (cherry picked from commit 5f2c78ef5b3b574d620aa3abe6a619c7deb143f5)
5bb5de4: EA-49160 (cherry picked from commit 2e82518e58e42959f9153f2685a1fb6c924b524e)
d33f8a2: NPE(EA-52907). (cherry picked from commit b44000de9a05193e218d159565a40e10d0770afa)
eb15fe6: IOOBE (EA-53138). (cherry picked from commit 1ac0a958e7902e9503b1584aa9a5099a5645592a)
5a76e10: SIOOBE(EA-53677). (cherry picked from commit 8e887d7)
d0de4d4: Fixed spelling in names of variables (cherry picked from commit e37f9b1)
43d19a0: Simplified always true expressions (cherry picked from commit 61f5888)
0d1f896: Fixed EA-49990: assert: TextRange.<init>
bf30c71: Fixed EA-52685 - assert: MultiHostRegistrarImpl.doneInjecting
845984e: Reordered methods (cherry picked from commit 35afccf)
4bd4b91: Fixed SQL 'select/insert/...' rule injection into indented string literals (PY-11970) (cherry picked from commit 5fd0a91)
afc90e9: Assume that string without '%' operator or 'format()' contains no formatting (PY-11771) (cherry picked from commit 2621f17)
58b30ff: Don't run code analysis for injections with interpolation in string formatting (PY-11962) (cherry picked from commit 6e66b22)
e7ff3f0: Add injection place even if a string fragment consists of zero chunks (cherry picked from commit e4bf6e4)
077db26: Fixed parsing of unbalanced new style string formatting (PY-11962) (cherry picked from commit 76e0d23)
d1d3177: IDEA-56096 Allow to create file templates with extension contains dot [CR-IC-3923] (cherry picked from commit c1728ca)
ef7c9e4: assume custom stubs only if psifile's content element type isn't IStubElementType, this fixes performance problem of previous change (that added support for dom indices). The performance problem was manifested for flex stubs produced by decompiler. (cherry picked from commit 4b5b6e8)
7ab32ff: IDEA-119773 (slf4j placeholder inspection false warnings when passing in Object array) (cherry picked from commit d8e1c94)
f6951b4: high CPU and EditorTextField/LanguageConsole scrolling
ef19cd4: [git] IDEA-119887 Support one more git version output format
6ebae26: [git] convert GitVersionTest to junit
86970d3: Add brokenPlugins.json
2f5b006: [^Peter] IDEA-117390 don't complete light elements containing IntelliJIdeaRulezzz
3abd741: [^peter]IDEA-119647 CCE on groovy file
585208a: Merge remote-tracking branch 'origin/133' into 133
6257aa0: PyCharm 3.1
a7af6ae: Gradle: buildscript configuration respect inheritance (cherry picked from commit 0f133cf)
d2311e1: [github] IDEA-119693 Don't share workspace.xml
8ed66a5: EA-53411 (more reliable diagnostic and better recovery)
7ac7972: IDEA-119498 (only suppress plugin updates for true command-line usage)
db1690c: IDEA-55171 (prevent sync refresh from locking if application is disposed)
f9286bb: fixed merge problem: extra test method was added
5b068d0: Traverse class owners via ScopeUtil in order to prevent switching from stubs to AST
527b224: Compare decorators by name preventing unnecessary switch from stubs to AST
d4d3308: Fix CCE (PY-10999).
8e0523a: Setup __loader__ for __main__ module (PY-10535).
273934b: Added test for PY-11337
989d3a3: PY-3569 Inspection to warn if a loop variable is assigned inside the loop
44efd68: fixed EA-53497 - assert: TextRange.<init>
85c7dee: better fix for IDEA-111684 (cherry picked from commit bb558e8)
50207de: 13.0.3 EAP
e3dcc49: IDEA-103743 Settings > Code Style > Arrangement UI glitch (after-review improvement) (cherry picked from commit 4269a85)
f6d1bd3: 1) IDEA-103743 Settings > Code Style > Arrangement UI glitch 2) checkbox unselection doesn't disable combobox (cherry picked from commit b788397)
e145138: Do not allow view to be larger than viewport with SCROLLBAR_NEVER policy
5ea4a3b: IDEA-118601 New Module: Maven: click on "Create from archetype" reverts typed coordinates. (cherry picked from commit 34d1109) +review CR-IC-3798
83fe636: hotfix: IDEA-119851 Gradle: the "out-of-process" mode doesn't work
0d06fcd: Merge branch '133' of git.labs.intellij.net:idea/community into 133
c1c74dc: Revert "updated external tools. Added annoying *.whl for the needs of virtualenv."
5e91a0d: advance bomb
37c6d1b: add read action (EA-51111)
239497a: read action
9f91062: PY-11882 Assignment to for loop inspection false positive PY-3569 Inspection to warn if a loop variable is assigned inside the loop
c571c78: Don't analyze target expressions not located in the current file
59eff48: PY-6955 Unused import not greyed out if also failing
2db3187: PY-6955 Unused import not greyed out if also failing
db42545: PY-6955 Unused import not greyed out if also failing (test refactored)
7aa1822: PY-3569 Inspection to warn if a loop variable is assigned inside the loop
086e91e: PY-3569 Inspection to warn if a loop variable is assigned inside the loop
a4d9d17: updated external tools. Added annoying *.whl for the needs of virtualenv.
e03288e: Cache presence or absence of a user skeleton for file in its user data
0f403e5: Rewritten PyQualifiedReference.collectAssignedAttributes() for better performance
cff2993: Cache the result of asQualifiedName()
938b089: Forgot call to super
5c00d1f: fixed missing sys import
7a48578: Disabled comment injector for Python for performance reasons
6e1a348: fixed missing sys import
ecc919e: fixed PY-11561 "Add super class call" incorrectly inserts parameter annotations
30556f2: fixed PY-11495 Create function: do not propose quick-fix for unresolved parts of fqn
3697485: fixed PY-11484 Implement abstract method: pushes docstring out of the way
5fa3f46: fixed isAbstractmethod
40ad42e: Fix align multiline elements in parenthesized expressions, parameters and arguments lists.
269d729: Cleanup of API for qualified names of expressions
51fb114: Method call in indenting statement should have continuation indent.
a29830e: fixed PY-11353 Creating Run Configuration from specific test gets the "target" wrong
4cbbccb: fixed PY-11312 False positive CamelCase variable imported as lowercase
72ace3a: fixed PY-11281 Convert dict comprehension to dict call omits if expression
145c46c: Deprecated PyResolveUtil.treeCrawlUp() as a slow way of traversing the PSI
04eb283: Made several internal methods of PyResolveUtil private
ffe45f7: fixed PY-11277 Python: Wrong "argument equals default" inspection
819364e: fixed PY-11617 Nosetest runner: simple function tests cannot jump to source
9b389fc: fixed PY-11696 Cancel after adding new interpreter removes configured project interpreter
a74d7e3: proper fix for PY-11879
23a7505: Added PyQualifiedReference.isQualified() that potentially doesn't require AST access
5991dac: Use ScopeUtil.getScopeOwner() for preventing unnecessary stubs to AST switch
04a4e01: fixed PY-11340 Invalid case for can't assign to literal inspection
0f03c21: fixed PY-11341 Invalid case for identifier expected inspection after as in with statement
90143fb: Fix continuation indentation in while statement (PY-11869).
bba7892: default test runner is unittest
92d2caf: Cache the results of asQualifiedName() for performance reasons
7a9fffc: Indent comment in tuple (PY-11904).
5c7ac44: Fixed test data to satisfy PEP8.
1d845d9: fixed PY-11879 Refactor: Rename: references in ivar directive are not updated
50bcfc0: fixed PY-11884 Missing completion for finally keyword after else statement
f2a14b8: Insert two spaces before line comment (PY-11901).
17e208c: Fix indent in parenthesized expression in indenting statement (PY-11868).
04c1a4a: Inject SQL only into strings that have SELECT/UPDATE... at the beginning
40ddc62: fixed PY-11428 "Variable in function should be lowercase" false positive for variables declared global
e214615: Try stub-based containers for Python PSI elements instead of getParent()
b7f8286: Use hasDefaultValue() instead of getDefaultValue() in order to prevent switching from stubs to AST
4831476: Qualified targets are never local
68e8c17: Use isQualified() instead of getQualifier() in order to prevent switching from stubs to AST
d351953: Find owner via ScopeUtil in order to prevent switching from stubs to AST
28b4b21: Note about stubs to AST
65a8a45: Traverse class owners via ScopeUtil in order to prevent switching from stubs to AST
51aef87: Compare decorators by name preventing unnecessary switch from stubs to AST
df0f3bb: Fixed NPE
9da12c1: Calculate iteration type via types, not PyClass elements
ae275ce: fixed PY-11875 Pycharm code analysis stalls on specific code (caused by AIOOB in getArguments of decorator)
a38300c: Removed redundant PyTypeProvider.getIterationType()
8e05ff9: Types of Enum members' fields and type of Enum.__members__
94cb03f: Fixed PyABCUtil.isSubtype() check for class definitions that have metaclasses
0060111: Type provider for enum.Enum members
cbb65bb: Store metaclass qualified name in class stub for better performance
79b43ed: Added PyClass.getMetaClassExpression()
7916719: Extracted getMetaClassExpression()
44a5f41: Evaluate metaclass type using TypeEvalContext
55fdf8e: Check __metaclass__ attribute only for Python 2.x
7afe4fc: Refactored PyUtil.getMetaClass() into PyClass.getMetaClassType()
14f98ae: Keywords already contains 'as' and 'with'
c38e6a3: Merge PyKeywords with PyNames
c4a0746: Extracted PyStdlibTypeProvider.getNamedTupleType()
Change-Id: Ia6001b030336ec63b47f7b49d53a595cc7fc0598
diff --git a/bin/WinLauncher/WinLauncher.exe b/bin/WinLauncher/WinLauncher.exe
index 38287df..3a08556 100644
--- a/bin/WinLauncher/WinLauncher.exe
+++ b/bin/WinLauncher/WinLauncher.exe
Binary files differ
diff --git a/bin/WinLauncher/WinLauncher64.exe b/bin/WinLauncher/WinLauncher64.exe
index e2e4348..1daf83c 100644
--- a/bin/WinLauncher/WinLauncher64.exe
+++ b/bin/WinLauncher/WinLauncher64.exe
Binary files differ
diff --git a/community-resources/src/idea/IdeaApplicationInfo.xml b/community-resources/src/idea/IdeaApplicationInfo.xml
index 08f4adb..9dbef92 100644
--- a/community-resources/src/idea/IdeaApplicationInfo.xml
+++ b/community-resources/src/idea/IdeaApplicationInfo.xml
@@ -1,5 +1,5 @@
<component>
- <version codename="Community Edition" major="13" minor="0.2" eap="false"/>
+ <version codename="Community Edition" major="13" minor="0.3" eap="true"/>
<company name="JetBrains s.r.o." url="http://www.jetbrains.com/?fromIDE"/>
<build number="__BUILD_NUMBER__" date="__BUILD_DATE__"/>
<install-over minbuild="129.1" maxbuild="132.9999" version="12.1"/>
diff --git a/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java b/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java
index 1a93b8c..4190b85 100644
--- a/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java
+++ b/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java
@@ -73,27 +73,27 @@
@NonNls public static final String PACKAGE_SUMMARY_FILE = "package-summary.html";
@Override
- public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
- if (element instanceof PsiClass) {
- return generateClassInfo((PsiClass)element);
- }
- else if (element instanceof PsiMethod) {
- return generateMethodInfo((PsiMethod)element, calcSubstitutor(originalElement));
- }
- else if (element instanceof PsiField) {
- return generateFieldInfo((PsiField)element, calcSubstitutor(originalElement));
- }
- else if (element instanceof PsiVariable) {
- return generateVariableInfo((PsiVariable)element);
- }
- else if (element instanceof PsiPackage) {
- return generatePackageInfo((PsiPackage)element);
- }
- else if (element instanceof BeanPropertyElement) {
- return generateMethodInfo(((BeanPropertyElement) element).getMethod(), PsiSubstitutor.EMPTY);
- }
- return null;
- }
+ public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
+ if (element instanceof PsiClass) {
+ return generateClassInfo((PsiClass)element);
+ }
+ else if (element instanceof PsiMethod) {
+ return generateMethodInfo((PsiMethod)element, calcSubstitutor(originalElement));
+ }
+ else if (element instanceof PsiField) {
+ return generateFieldInfo((PsiField)element, calcSubstitutor(originalElement));
+ }
+ else if (element instanceof PsiVariable) {
+ return generateVariableInfo((PsiVariable)element);
+ }
+ else if (element instanceof PsiPackage) {
+ return generatePackageInfo((PsiPackage)element);
+ }
+ else if (element instanceof BeanPropertyElement) {
+ return generateMethodInfo(((BeanPropertyElement) element).getMethod(), PsiSubstitutor.EMPTY);
+ }
+ return null;
+ }
private static PsiSubstitutor calcSubstitutor(PsiElement originalElement) {
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
@@ -115,20 +115,13 @@
}
private static void generateInitializer(StringBuilder buffer, PsiVariable variable) {
- PsiExpression initializer = JavaDocInfoGenerator.calcInitializerExpression(variable);
+ PsiExpression initializer = variable.getInitializer();
if (initializer != null) {
- String text = initializer.getText().trim();
- int index1 = text.indexOf('\n');
- if (index1 < 0) index1 = text.length();
- int index2 = text.indexOf('\r');
- if (index2 < 0) index2 = text.length();
- int index = Math.min(index1, index2);
- boolean trunc = index < text.length();
- text = text.substring(0, index);
- buffer.append(" = ");
- buffer.append(StringUtil.escapeXml(text));
- if (trunc) {
- buffer.append("...");
+ JavaDocInfoGenerator.appendExpressionValue(buffer, initializer, " = ");
+ PsiExpression constantInitializer = JavaDocInfoGenerator.calcInitializerExpression(variable);
+ if (constantInitializer != null) {
+ buffer.append("\n");
+ JavaDocInfoGenerator.appendExpressionValue(buffer, constantInitializer, CodeInsightBundle.message("javadoc.resolved.value"));
}
}
}
diff --git a/java/java-psi-api/src/com/intellij/psi/util/TypesDistinctProver.java b/java/java-psi-api/src/com/intellij/psi/util/TypesDistinctProver.java
index 381eabc..e147b40 100644
--- a/java/java-psi-api/src/com/intellij/psi/util/TypesDistinctProver.java
+++ b/java/java-psi-api/src/com/intellij/psi/util/TypesDistinctProver.java
@@ -104,9 +104,15 @@
for (PsiTypeParameter parameter : substitutor1.getSubstitutionMap().keySet()) {
final PsiType substitutedType1 = substitutor1.substitute(parameter);
final PsiType substitutedType2 = substitutor2.substitute(parameter);
- if (substitutedType1 == null && substitutedType2 == null) return false;
- if (substitutedType1 == null || substitutedType2 == null) {
- return true;
+ if (substitutedType1 == null && substitutedType2 == null){
+ continue;
+ }
+
+ if (substitutedType1 == null) {
+ if (type2 instanceof PsiClassType && ((PsiClassType)type2).hasParameters()) return true;
+ }
+ else if (substitutedType2 == null) {
+ if (type1 instanceof PsiClassType && ((PsiClassType)type1).hasParameters()) return true;
} else {
if (provablyDistinct(substitutedType1, substitutedType2, level + 1)) return true;
if (substitutedType1 instanceof PsiWildcardType && !((PsiWildcardType)substitutedType1).isBounded()) return true;
diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java b/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java
index 11de043..d9ec369 100644
--- a/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java
+++ b/java/java-psi-impl/src/com/intellij/codeInsight/ExceptionUtil.java
@@ -421,8 +421,12 @@
@Override
public Pair<PsiMethod, PsiSubstitutor> fun(CandidateInfo info) {
PsiElement element = info.getElement();
- return element instanceof PsiMethod && MethodSignatureUtil.areSignaturesEqual(method, (PsiMethod)element)
- ? Pair.create((PsiMethod)element, info.getSubstitutor()) : null;
+ if (element instanceof PsiMethod &&
+ MethodSignatureUtil.areSignaturesEqual(method, (PsiMethod)element) &&
+ !MethodSignatureUtil.isSuperMethod((PsiMethod)element, method)) {
+ return Pair.create((PsiMethod)element, info.getSubstitutor());
+ }
+ return null;
}
});
if (candidates.size() > 1) {
@@ -456,8 +460,10 @@
found = true;
break;
} else if (classType.isAssignableFrom(psiClassType)) {
- replacement.add(psiClassType);
- iterator.remove();
+ if (isUncheckedException(classType) == isUncheckedException(psiClassType)) {
+ replacement.add(psiClassType);
+ iterator.remove();
+ }
found = true;
break;
}
diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java
index 432d9d7..23b1d30 100644
--- a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java
+++ b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java
@@ -73,7 +73,7 @@
private final Project myProject;
private final PsiElement myElement;
-
+
interface InheritDocProvider<T> {
Pair<T, InheritDocProvider<T>> getInheritDoc();
@@ -592,7 +592,7 @@
generateEpilogue(buffer);
}
- public static PsiExpression calcInitializerExpression(PsiVariable variable) {
+ public static @Nullable PsiExpression calcInitializerExpression(PsiVariable variable) {
PsiExpression initializer = variable.getInitializer();
if (initializer != null) {
PsiModifierList modifierList = variable.getModifierList();
@@ -606,15 +606,36 @@
text = "\"" + StringUtil.trimLog(text, 120) + "\"";
}
else if (type.equalsToText("char")) text = "'" + text + "'";
- initializer = instance.getElementFactory().createExpressionFromText(text, variable);
+ try {
+ return instance.getElementFactory().createExpressionFromText(text, variable);
+ } catch (IncorrectOperationException ex) {
+ LOG.error(text, ex);
+ }
}
}
}
- return initializer;
+ return null;
+ }
+
+ public static boolean appendExpressionValue(StringBuilder buffer, PsiExpression initializer, String label) {
+ String text = initializer.getText().trim();
+ int index1 = text.indexOf('\n');
+ if (index1 < 0) index1 = text.length();
+ int index2 = text.indexOf('\r');
+ if (index2 < 0) index2 = text.length();
+ int index = Math.min(index1, index2);
+ boolean trunc = index < text.length();
+ text = text.substring(0, index);
+ buffer.append(label);
+ buffer.append(StringUtil.escapeXml(text));
+ if (trunc) {
+ buffer.append("...");
+ }
+ return trunc;
}
private static void appendInitializer(StringBuilder buffer, PsiVariable variable) {
- PsiExpression initializer = calcInitializerExpression(variable);
+ PsiExpression initializer = variable.getInitializer();
if (initializer != null) {
buffer.append(" = ");
@@ -634,6 +655,11 @@
else {
initializer.accept(new MyVisitor(buffer));
}
+ PsiExpression constantInitializer = calcInitializerExpression(variable);
+ if (constantInitializer != null) {
+ buffer.append("\n");
+ appendExpressionValue(buffer, constantInitializer, CodeInsightBundle.message("javadoc.resolved.value"));
+ }
}
}
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java
index 3096f24..534b4c7 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java
@@ -17,6 +17,7 @@
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiSubstitutorImpl;
@@ -128,6 +129,7 @@
}
index++;
}
+ collectOuterClassTypeArgs(((PsiClass)resolve), myCanonicalText, substitutionMap);
return new CandidateInfo(resolve, PsiSubstitutorImpl.createSubstitutor(substitutionMap));
}
else {
@@ -135,6 +137,24 @@
}
}
+ private void collectOuterClassTypeArgs(final PsiClass psiClass,
+ final String canonicalText,
+ final Map<PsiTypeParameter, PsiType> substitutionMap) {
+ final PsiClass containingClass = psiClass.getContainingClass();
+ if (containingClass != null && !containingClass.hasModifierProperty(PsiModifier.STATIC)) {
+ final String outerClassRef = StringUtil.getPackageName(canonicalText);
+ final String[] classParameters = PsiNameHelper.getClassParametersText(outerClassRef);
+ final PsiType[] args = classParameters.length == 0 ? null : new ClsReferenceParameterListImpl(this, classParameters).getTypeArguments();
+ final PsiTypeParameter[] typeParameters = containingClass.getTypeParameters();
+ for (int i = 0; i < typeParameters.length; i++) {
+ if (args != null && i < args.length) {
+ substitutionMap.put(typeParameters[i], args[i]);
+ }
+ }
+ collectOuterClassTypeArgs(containingClass, outerClassRef, substitutionMap);
+ }
+ }
+
@Override
@NotNull
public JavaResolveResult advancedResolve(boolean incompleteCode) {
diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java
index 22cc051..79c50b3 100644
--- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java
+++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java
@@ -28,6 +28,7 @@
import com.intellij.psi.scope.PsiConflictResolver;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.*;
+import com.intellij.util.ArrayUtilRt;
import com.intellij.util.containers.HashSet;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
@@ -35,10 +36,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
/**
* Created by IntelliJ IDEA.
@@ -506,10 +504,11 @@
final PsiSubstitutor siteSubstitutor1 = ((MethodCandidateInfo)info1).getSiteSubstitutor();
final PsiSubstitutor siteSubstitutor2 = ((MethodCandidateInfo)info2).getSiteSubstitutor();
- final PsiType[] types2AtSite = typesAtSite(types2, siteSubstitutor2);
- final PsiType[] types1AtSite = typesAtSite(types1, siteSubstitutor1);
+ final PsiType[] types2AtSite = typesAtSite(types2, siteSubstitutor2, typeParameters2);
+ final PsiType[] types1AtSite = typesAtSite(types1, siteSubstitutor1, typeParameters1);
- final PsiSubstitutor methodSubstitutor1 = calculateMethodSubstitutor(typeParameters1, method1, siteSubstitutor1, types1, types2AtSite, languageLevel);
+ final PsiSubstitutor methodSubstitutor1 = calculateMethodSubstitutor(typeParameters1, method1, siteSubstitutor1, types1, types2AtSite,
+ languageLevel);
boolean applicable12 = isApplicableTo(types2AtSite, method1, languageLevel, varargsPosition, methodSubstitutor1);
final PsiSubstitutor methodSubstitutor2 = calculateMethodSubstitutor(typeParameters2, method2, siteSubstitutor2, types2, types1AtSite, languageLevel);
@@ -641,14 +640,64 @@
return applicabilityLevel > MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE;
}
- private static PsiType[] typesAtSite(PsiType[] types1, PsiSubstitutor siteSubstitutor1) {
+ private static PsiType[] typesAtSite(PsiType[] types1, PsiSubstitutor siteSubstitutor1, PsiTypeParameter[] typeParameters1 ) {
final PsiType[] types = new PsiType[types1.length];
for (int i = 0; i < types1.length; i++) {
types[i] = siteSubstitutor1.substitute(types1[i]);
+ if (types[i] instanceof PsiClassType) {
+ final PsiClass aClass = ((PsiClassType)types[i]).resolve();
+ if (aClass instanceof PsiTypeParameter) {
+ final List<PsiType> resultBounds = new ArrayList<PsiType>();
+ for (PsiType bound : aClass.getExtendsListTypes()) {
+ bound = siteSubstitutor1.substitute(bound);
+ if (!dependsOnOtherTypeParams(bound, typeParameters1)) {
+ resultBounds.add(bound);
+ } else {
+ resultBounds.clear();
+ break;
+ }
+ }
+ if (!resultBounds.isEmpty()) {
+ types[i] = PsiIntersectionType.createIntersection(resultBounds);
+ }
+ }
+ }
}
return types;
}
+ private static boolean dependsOnOtherTypeParams(PsiType type, final PsiTypeParameter[] params) {
+ return type.accept(new PsiTypeVisitor<Boolean>(){
+ @Nullable
+ @Override
+ public Boolean visitClassType(PsiClassType classType) {
+ for (PsiType psiType : classType.getParameters()) {
+ if (psiType.accept(this)) return true;
+ }
+ return ArrayUtilRt.find(params, classType.resolve()) > -1;
+ }
+
+ @Nullable
+ @Override
+ public Boolean visitArrayType(PsiArrayType arrayType) {
+ return arrayType.getComponentType().accept(this);
+ }
+
+ @Nullable
+ @Override
+ public Boolean visitWildcardType(PsiWildcardType wildcardType) {
+ final PsiType bound = wildcardType.getBound();
+ return bound != null && bound.accept(this);
+ }
+
+ @Nullable
+ @Override
+ public Boolean visitType(PsiType type) {
+ return false;
+ }
+ });
+ }
+
private static PsiSubstitutor calculateMethodSubstitutor(final PsiTypeParameter[] typeParameters,
final PsiMethod method,
final PsiSubstitutor siteSubstitutor,
@@ -661,7 +710,11 @@
ProgressManager.checkCanceled();
LOG.assertTrue(typeParameter != null);
if (!substitutor.getSubstitutionMap().containsKey(typeParameter)) {
- substitutor = substitutor.put(typeParameter, TypeConversionUtil.erasure(siteSubstitutor.substitute(typeParameter), substitutor));
+ PsiType type = siteSubstitutor.substitute(typeParameter);
+ if (type instanceof PsiClassType && ((PsiClassType)type).resolve() instanceof PsiTypeParameter) {
+ type = TypeConversionUtil.erasure(type, substitutor);
+ }
+ substitutor = substitutor.put(typeParameter, type);
}
}
return substitutor;
diff --git a/java/java-tests/testData/codeInsight/clsHighlighting/IDEA118733.java b/java/java-tests/testData/codeInsight/clsHighlighting/IDEA118733.java
new file mode 100644
index 0000000..9b2a124c
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/clsHighlighting/IDEA118733.java
@@ -0,0 +1,5 @@
+public class MyChild {
+ public void evaluate(Child child) {
+ Parent<String>.InnerBase i = child.foo();
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/clsHighlighting/IDEA97887.java b/java/java-tests/testData/codeInsight/clsHighlighting/IDEA97887.java
new file mode 100644
index 0000000..36c97bd
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/clsHighlighting/IDEA97887.java
@@ -0,0 +1,6 @@
+public class MyChild extends Child<String> {
+ @Override
+ public void evaluate(InnerImpl impl) {
+ String s = impl.t;
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA118733.jar b/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA118733.jar
new file mode 100644
index 0000000..bd96af3
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA118733.jar
Binary files differ
diff --git a/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA97887.jar b/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA97887.jar
new file mode 100644
index 0000000..cbc7bf18
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA97887.jar
Binary files differ
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/IgnoreSuperMethodsInMultipleOverridingCheck.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/IgnoreSuperMethodsInMultipleOverridingCheck.java
new file mode 100644
index 0000000..943e373
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/IgnoreSuperMethodsInMultipleOverridingCheck.java
@@ -0,0 +1,21 @@
+class SQLException extends java.lang.Exception{}
+
+interface ICompileErrorTest {
+ void foo() throws IllegalStateException, Exception;
+}
+
+abstract class CompileErrorTest implements ICompileErrorTest {
+ public void foo() throws Exception {
+ throw new SQLException();
+ }
+}
+
+public class CompileErrorTestExtended extends CompileErrorTest {
+ public void foo() throws Exception {
+ try {
+ super.foo();
+ } catch (SQLException ignore) {
+ }
+ }
+}
+
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA118527.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA118527.java
new file mode 100644
index 0000000..a365bad
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA118527.java
@@ -0,0 +1,48 @@
+
+interface Listener<A0, B0> {}
+class Adapter<A, B> implements Listener<A, B> {}
+class Super<O, B> {
+ public <C extends Adapter<O, B>> C apply(C configurer) throws Exception {
+ return null;
+ }
+
+ public <C extends Listener<O, B>> C apply(C configurer) throws Exception {
+ return null;
+ }
+}
+
+class AdapterImpl extends Adapter<String, String>{}
+
+class Child<O, B> extends Super<O, B> {}
+class D {
+
+ void foo(Child<String, String> ch, AdapterImpl a) throws Exception {
+ ch.apply(a);
+ }
+}
+
+class Test {
+ interface Listener<A0, B0> {}
+ class Adapter<A, B> implements Listener<A, B> {}
+ class Super<O, B> {
+ public <C extends Adapter<O, B> & Runnable> C apply(C configurer) throws Exception {
+ return null;
+ }
+
+ public <C extends Listener<O, B> & Runnable> C apply(C configurer) throws Exception {
+ return null;
+ }
+ }
+
+ abstract class AdapterImpl extends Adapter<String, String> implements Runnable{}
+
+ class Child<O, B> extends Super<O, B> {}
+ class D {
+
+ void foo(Child<String, String> ch, AdapterImpl a) throws Exception {
+ ch.apply( a);
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA119546.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA119546.java
new file mode 100644
index 0000000..7eeb837
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA119546.java
@@ -0,0 +1,9 @@
+public interface I<K> {
+}
+
+abstract class SpringHighlightingTestCase<T extends I>{
+ @SuppressWarnings("unchecked")
+ protected Class<T> getBuilderClass() {
+ return (Class<T>)I.class;
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA120153.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA120153.java
new file mode 100644
index 0000000..afca963
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA120153.java
@@ -0,0 +1,23 @@
+import java.util.Collection;
+import java.util.List;
+
+class Idea {
+ class Library<T> {
+ public void f(Base<T> x) {
+ }
+ public void f(Derived<T> x) {
+ }
+ }
+
+ class Wrapper<T> {
+ }
+
+ class Base<In> {
+ }
+ class Derived<In> extends Base<In> {
+ }
+
+ public void main(Derived<Wrapper<String>> x) {
+ new Library<Wrapper<String>>().f(x);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/javadocIG/constantFieldInitializer.html b/java/java-tests/testData/codeInsight/javadocIG/constantFieldInitializer.html
new file mode 100644
index 0000000..3965d05
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadocIG/constantFieldInitializer.html
@@ -0,0 +1,2 @@
+<html><head> <style type="text/css"> #error { background-color: #eeeeee; margin-bottom: 10px; } p { margin: 5px 0; } </style></head><body><small><b><a href="psi_element://Test"><code>Test</code></a></b></small><PRE>public static final int <b>field =
+Resolved value: 2</b></PRE></body></html>
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/javadocIG/constantFieldInitializer.java b/java/java-tests/testData/codeInsight/javadocIG/constantFieldInitializer.java
new file mode 100644
index 0000000..69753df
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadocIG/constantFieldInitializer.java
@@ -0,0 +1,3 @@
+class Test {
+ public static final int field = 1 + 1;
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenericsHighlightingTest.java
new file mode 100644
index 0000000..d9897f5
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenericsHighlightingTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * User: anna
+ * Date: 27-Jun-2007
+ */
+package com.intellij.codeInsight;
+
+import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInsight.intention.impl.DeannotateIntentionAction;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.ex.PathManagerEx;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.editor.CaretModel;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.AnnotationOrderRootType;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.LibraryTable;
+import com.intellij.openapi.util.Trinity;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.StreamUtil;
+import com.intellij.openapi.vfs.*;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.testFramework.IdeaTestCase;
+import com.intellij.testFramework.PsiTestUtil;
+import com.intellij.testFramework.UsefulTestCase;
+import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
+import com.intellij.testFramework.fixtures.*;
+import com.intellij.util.messages.MessageBusConnection;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ClsGenericsHighlightingTest extends UsefulTestCase {
+ private CodeInsightTestFixture myFixture;
+ private Module myModule;
+
+ public ClsGenericsHighlightingTest() {
+ IdeaTestCase.initPlatformPrefix();
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ final TestFixtureBuilder<IdeaProjectTestFixture> projectBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName());
+
+ myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(projectBuilder.getFixture());
+ final String dataPath = PathManagerEx.getTestDataPath() + "/codeInsight/clsHighlighting";
+ myFixture.setTestDataPath(dataPath);
+ final JavaModuleFixtureBuilder builder = projectBuilder.addModule(JavaModuleFixtureBuilder.class);
+ builder.setMockJdkLevel(JavaModuleFixtureBuilder.MockJdkLevel.jdk15);
+
+ myFixture.setUp();
+ myModule = builder.getFixture().getModule();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ myFixture.tearDown();
+ myFixture = null;
+ myModule = null;
+ }
+
+ private void addLibrary(@NotNull final String... libraryPath) {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ final ModifiableRootModel model = ModuleRootManager.getInstance(myModule).getModifiableModel();
+ final LibraryTable libraryTable = model.getModuleLibraryTable();
+ final Library library = libraryTable.createLibrary("test");
+
+ final Library.ModifiableModel libraryModel = library.getModifiableModel();
+ for (String annotationsDir : libraryPath) {
+ final VirtualFile libJarLocal = LocalFileSystem.getInstance().findFileByPath(myFixture.getTestDataPath() + "/libs/" + annotationsDir);
+ assertNotNull(libJarLocal);
+ final VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(libJarLocal);
+ assertNotNull(jarRoot);
+ libraryModel.addRoot(jarRoot , OrderRootType.CLASSES);
+ }
+ libraryModel.commit();
+ final String contentUrl = VfsUtilCore.pathToUrl(myFixture.getTempDirPath());
+ model.addContentEntry(contentUrl).addSourceFolder(contentUrl, false);
+ model.commit();
+ }
+ });
+ }
+
+ public void testIDEA97887() throws Throwable {
+ doTest();
+ }
+
+ public void testIDEA118733() throws Exception {
+ doTest();
+ }
+
+ private void doTest() {
+ addLibrary(getTestName(false) + ".jar");
+ myFixture.configureByFile(getTestName(false) + ".java");
+ myFixture.checkHighlighting();
+ }
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java
index 64798f4..9455c0e 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java
@@ -334,6 +334,9 @@
public void testIDEA116493() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
public void testIDEA117827() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
public void testIDEA118037() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
+ public void testIDEA119546() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
+ public void testIDEA118527() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
+ public void testIDEA120153() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
public void testJavaUtilCollections_NoVerify() throws Exception {
PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule()));
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java
index 37b9c4c..79c45a9 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java
@@ -119,6 +119,7 @@
public void testAssignToFinal() { doTest(false, false); }
public void testUnhandledExceptionsInSuperclass() { doTest(false, false); }
public void testNoUnhandledExceptionsMultipleInheritance() { doTest(false, false); }
+ public void testIgnoreSuperMethodsInMultipleOverridingCheck() { doTest(false, false); }
public void testFalseExceptionsMultipleInheritance() { doTest(true, false); }
public void testAssignmentCompatible () { setLanguageLevel(LanguageLevel.JDK_1_5); doTest(false, false); }
public void testMustBeBoolean() { doTest(false, false); }
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java
index 80d2e4a..757b74e 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java
@@ -55,6 +55,10 @@
public void testEnumValueOf() throws Exception {
doTestMethod();
}
+
+ public void testConstantFieldInitializer() throws Exception {
+ doTestField();
+ }
public void testInitializerWithNew() throws Exception {
doTestField();
diff --git a/java/java-tests/testSrc/com/intellij/ide/fileTemplates/FileTemplatesTest.groovy b/java/java-tests/testSrc/com/intellij/ide/fileTemplates/FileTemplatesTest.groovy
index fb06e42..b0d93af 100644
--- a/java/java-tests/testSrc/com/intellij/ide/fileTemplates/FileTemplatesTest.groovy
+++ b/java/java-tests/testSrc/com/intellij/ide/fileTemplates/FileTemplatesTest.groovy
@@ -1,5 +1,6 @@
package com.intellij.ide.fileTemplates
import com.intellij.ide.fileTemplates.impl.CustomFileTemplate
+import com.intellij.ide.fileTemplates.impl.FileTemplateTestUtil
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ex.PathManagerEx
import com.intellij.openapi.roots.ModuleRootManager
@@ -16,6 +17,16 @@
import com.intellij.util.properties.EncodingAwareProperties
public class FileTemplatesTest extends IdeaTestCase {
+ private File myTestConfigDir;
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if (myTestConfigDir !=null && myTestConfigDir.exists()) {
+ FileUtil.delete(myTestConfigDir);
+ }
+ }
+
public void testAllTemplates() throws Exception {
final File testsDir = new File(PathManagerEx.getTestDataPath()+"/ide/fileTemplates");
@@ -130,4 +141,38 @@
template.setText(text);
template
}
+
+ public void doTestSaveLoadTemplate(String name, String ext) {
+ FileTemplateTestUtil.TestFTManager templateManager = new FileTemplateTestUtil.TestFTManager("test", "testTemplates",
+ getTestConfigRoot());
+ FileTemplate template = templateManager.addTemplate(name, ext);
+ String qName = template.getQualifiedName();
+ templateManager.saveTemplates();
+ templateManager.removeTemplate(qName);
+ FileTemplateTestUtil.loadCustomizedContent(templateManager);
+ FileTemplate loadedTemplate = templateManager.findTemplateByName(name);
+ assertNotNull("Template '" + qName + "' was not found", loadedTemplate);
+ assertEquals(name, loadedTemplate.getName());
+ assertEquals(ext, loadedTemplate.getExtension());
+ assertTrue(template != loadedTemplate);
+ }
+
+ private File getTestConfigRoot() throws Exception {
+ if (myTestConfigDir == null) {
+ myTestConfigDir = FileUtil.createTempDirectory(getTestName(true), "config");
+ }
+ return myTestConfigDir;
+ }
+
+ public void testSaveLoadCustomTemplate() throws Exception {
+ doTestSaveLoadTemplate("name", "ext");
+ }
+
+ public void testSaveLoadCustomTemplateDottedName() throws Exception {
+ doTestSaveLoadTemplate("name.has.dots", "ext");
+ }
+
+ public void testSaveLoadCustomTemplateDottedExt() throws Exception {
+ doTestSaveLoadTemplate("name", "ext.has.dots");
+ }
}
diff --git a/java/java-tests/testSrc/com/intellij/ide/fileTemplates/impl/FileTemplateTestUtil.java b/java/java-tests/testSrc/com/intellij/ide/fileTemplates/impl/FileTemplateTestUtil.java
new file mode 100644
index 0000000..7dbf802
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/ide/fileTemplates/impl/FileTemplateTestUtil.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.ide.fileTemplates.impl;
+
+import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+
+/**
+ * @author Rustam Vishnyakov
+ */
+public class FileTemplateTestUtil {
+ public static final class TestFTManager extends FTManager {
+ private File myTestConfigDir;
+
+ public TestFTManager(
+ @NotNull @NonNls String name,
+ @NotNull @NonNls String defaultTemplatesDirName,
+ @NotNull File testConfigDir) {
+ super(name, defaultTemplatesDirName);
+ myTestConfigDir = testConfigDir;
+ }
+
+ @Override
+ public File getConfigRoot(boolean create) {
+ return myTestConfigDir;
+ }
+
+ @Override
+ public void saveTemplates() {
+ super.saveTemplates();
+ }
+ }
+
+ public static void loadCustomizedContent(FTManager templateManager) {
+ FileTemplatesLoader loader = new FileTemplatesLoader(FileTypeManagerEx.getInstanceEx());
+ loader.loadCustomizedContent(templateManager);
+ }
+}
diff --git a/native/WinLauncher/WinLauncher/WinLauncher.cpp b/native/WinLauncher/WinLauncher/WinLauncher.cpp
index 8d5ff13..a934a88 100644
--- a/native/WinLauncher/WinLauncher/WinLauncher.cpp
+++ b/native/WinLauncher/WinLauncher/WinLauncher.cpp
@@ -17,7 +17,7 @@
#include "stdafx.h"
#include "WinLauncher.h"
-typedef JNIIMPORT jint (JNICALL *JNI_createJavaVM)(JavaVM **pvm, JNIEnv **env, void *args);
+typedef JNIIMPORT jint(JNICALL *JNI_createJavaVM)(JavaVM **pvm, JNIEnv **env, void *args);
HINSTANCE hInst; // current instance
char jvmPath[_MAX_PATH];
@@ -45,7 +45,7 @@
{
wchar_t *buf = NULL;
int len = LoadStringW(hInst, id, reinterpret_cast<LPWSTR>(&buf), 0);
- if (len)
+ if (len)
{
int cbANSI = WideCharToMultiByte(CP_ACP, 0, buf, len, NULL, 0, NULL, NULL);
char* ansiBuf = new char[cbANSI];
@@ -65,7 +65,7 @@
bool IsValidJRE(const char* path)
{
std::string dllPath(path);
- if (dllPath[dllPath.size()-1] != '\\')
+ if (dllPath[dllPath.size() - 1] != '\\')
{
dllPath += "\\";
}
@@ -83,16 +83,16 @@
{
if (IsValidJRE(path))
{
- strcpy_s(jvmPath, _MAX_PATH-1, path);
+ strcpy_s(jvmPath, _MAX_PATH - 1, path);
return true;
}
char jrePath[_MAX_PATH];
strcpy_s(jrePath, path);
- if (jrePath[strlen(jrePath)-1] != '\\')
+ if (jrePath[strlen(jrePath) - 1] != '\\')
{
strcat_s(jrePath, "\\");
}
- strcat_s(jrePath, _MAX_PATH-1, "jre");
+ strcat_s(jrePath, _MAX_PATH - 1, "jre");
if (IsValidJRE(jrePath))
{
strcpy_s(jvmPath, jrePath);
@@ -104,13 +104,13 @@
std::string GetAdjacentDir(const char* suffix)
{
char libDir[_MAX_PATH];
- GetModuleFileNameA(NULL, libDir, _MAX_PATH-1);
+ GetModuleFileNameA(NULL, libDir, _MAX_PATH - 1);
char* lastSlash = strrchr(libDir, '\\');
if (!lastSlash) return "";
*lastSlash = '\0';
lastSlash = strrchr(libDir, '\\');
if (!lastSlash) return "";
- strcpy(lastSlash+1, suffix);
+ strcpy(lastSlash + 1, suffix);
strcat_s(libDir, "\\");
return std::string(libDir);
}
@@ -118,7 +118,7 @@
bool FindJVMInEnvVar(const char* envVarName, bool& result)
{
char envVarValue[_MAX_PATH];
- if (GetEnvironmentVariableA(envVarName, envVarValue, _MAX_PATH-1))
+ if (GetEnvironmentVariableA(envVarName, envVarValue, _MAX_PATH - 1))
{
if (FindValidJVM(envVarValue))
{
@@ -145,9 +145,9 @@
if (wow64_32) flags |= KEY_WOW64_32KEY;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey) != ERROR_SUCCESS) return false;
char javaHome[_MAX_PATH];
- DWORD javaHomeSize = _MAX_PATH-1;
+ DWORD javaHomeSize = _MAX_PATH - 1;
bool success = false;
- if (RegQueryValueExA(hKey, "JavaHome", NULL, NULL, (LPBYTE) javaHome, &javaHomeSize) == ERROR_SUCCESS)
+ if (RegQueryValueExA(hKey, "JavaHome", NULL, NULL, (LPBYTE)javaHome, &javaHomeSize) == ERROR_SUCCESS)
{
success = FindValidJVM(javaHome);
}
@@ -157,7 +157,7 @@
bool FindJVMInRegistryWithVersion(const char* version, bool wow64_32)
{
- const char* keyName = LoadStdString(IDS_JDK_ONLY) == std::string("true")
+ const char* keyName = LoadStdString(IDS_JDK_ONLY) == std::string("true")
? "Java Development Kit"
: "Java Runtime Environment";
@@ -217,7 +217,7 @@
{
*p-- = '\0';
}
- while(p >= line && (*p == ' ' || *p == '\t'))
+ while (p >= line && (*p == ' ' || *p == '\t'))
{
*p-- = '\0';
}
@@ -227,9 +227,9 @@
{
FILE *f = _tfopen(path, _T("rt"));
if (!f) return false;
-
+
char line[_MAX_PATH];
- while(fgets(line, _MAX_PATH-1, f))
+ while (fgets(line, _MAX_PATH - 1, f))
{
TrimLine(line);
if (line[0] == '#') continue;
@@ -253,7 +253,7 @@
size_t lastSlash = toolsJarPath.rfind('\\');
if (lastSlash != std::string::npos)
{
- toolsJarPath = toolsJarPath.substr(0, lastSlash+1) + "lib\\tools.jar";
+ toolsJarPath = toolsJarPath.substr(0, lastSlash + 1) + "lib\\tools.jar";
if (FileExists(toolsJarPath))
{
return toolsJarPath;
@@ -272,7 +272,7 @@
std::string result;
int pos = 0;
- while(pos < jarList.size())
+ while (pos < jarList.size())
{
int delimiterPos = jarList.find(';', pos);
if (delimiterPos == std::string::npos)
@@ -284,8 +284,8 @@
result += ";";
}
result += libDir;
- result += jarList.substr(pos, delimiterPos-pos);
- pos = delimiterPos+1;
+ result += jarList.substr(pos, delimiterPos - pos);
+ pos = delimiterPos + 1;
}
return result;
}
@@ -324,17 +324,17 @@
void AddPredefinedVMOptions(std::vector<std::string>& vmOptionLines)
{
std::string vmOptions = LoadStdString(IDS_VM_OPTIONS);
- while(vmOptions.size() > 0)
+ while (vmOptions.size() > 0)
{
int pos = vmOptions.find(' ');
if (pos == std::string::npos) pos = vmOptions.size();
vmOptionLines.push_back(vmOptions.substr(0, pos));
- while(pos < vmOptions.size() && vmOptions[pos] == ' ') pos++;
+ while (pos < vmOptions.size() && vmOptions[pos] == ' ') pos++;
vmOptions = vmOptions.substr(pos);
}
char ideaProperties[_MAX_PATH];
- if (GetEnvironmentVariableA("IDEA_PROPERTIES", ideaProperties, _MAX_PATH-1))
+ if (GetEnvironmentVariableA("IDEA_PROPERTIES", ideaProperties, _MAX_PATH - 1))
{
vmOptionLines.push_back(std::string("-Didea.properties.file=") + ideaProperties);
}
@@ -343,17 +343,17 @@
bool LoadVMOptions()
{
TCHAR optionsFileName[_MAX_PATH];
- if (LoadString(hInst, IDS_VM_OPTIONS_PATH, optionsFileName, _MAX_PATH-1))
+ if (LoadString(hInst, IDS_VM_OPTIONS_PATH, optionsFileName, _MAX_PATH - 1))
{
TCHAR fullOptionsFileName[_MAX_PATH];
- ExpandEnvironmentStrings(optionsFileName, fullOptionsFileName, _MAX_PATH-1);
-
+ ExpandEnvironmentStrings(optionsFileName, fullOptionsFileName, _MAX_PATH - 1);
+
if (GetFileAttributes(fullOptionsFileName) == INVALID_FILE_ATTRIBUTES)
{
- GetModuleFileName(NULL, fullOptionsFileName, _MAX_PATH-1);
+ GetModuleFileName(NULL, fullOptionsFileName, _MAX_PATH - 1);
_tcscat_s(fullOptionsFileName, _T(".vmoptions"));
}
-
+
std::vector<std::string> vmOptionLines;
if (LoadVMOptionsFile(fullOptionsFileName, vmOptionLines))
{
@@ -361,8 +361,8 @@
AddPredefinedVMOptions(vmOptionLines);
vmOptionCount = vmOptionLines.size();
- vmOptions = (JavaVMOption*) malloc(vmOptionCount * sizeof(JavaVMOption));
- for(int i=0; i<vmOptionLines.size(); i++)
+ vmOptions = (JavaVMOption*)malloc(vmOptionCount * sizeof(JavaVMOption));
+ for (int i = 0; i < vmOptionLines.size(); i++)
{
vmOptions[i].optionString = _strdup(vmOptionLines[i].c_str());
vmOptions[i].extraInfo = 0;
@@ -394,7 +394,7 @@
hJVM = LoadLibraryA(dllName.c_str());
if (hJVM)
{
- pCreateJavaVM = (JNI_createJavaVM) GetProcAddress(hJVM, "JNI_CreateJavaVM");
+ pCreateJavaVM = (JNI_createJavaVM)GetProcAddress(hJVM, "JNI_CreateJavaVM");
}
if (!pCreateJavaVM)
{
@@ -416,7 +416,7 @@
int result = pCreateJavaVM(&jvm, &env, &initArgs);
- for(int i=0; i<vmOptionCount; i++)
+ for (int i = 0; i < vmOptionCount; i++)
{
free(vmOptions[i].optionString);
}
@@ -438,11 +438,11 @@
int numArgs;
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &numArgs);
jclass stringClass = env->FindClass("java/lang/String");
- jobjectArray args = env->NewObjectArray(numArgs-1, stringClass, NULL);
- for(int i=1; i<numArgs; i++)
+ jobjectArray args = env->NewObjectArray(numArgs - 1, stringClass, NULL);
+ for (int i = 1; i < numArgs; i++)
{
const wchar_t* arg = argv[i];
- env->SetObjectArrayElement(args, i-1, env->NewString((const jchar *) arg, wcslen(argv[i])));
+ env->SetObjectArrayElement(args, i - 1, env->NewString((const jchar *)arg, wcslen(argv[i])));
}
return args;
}
@@ -484,7 +484,7 @@
attachArgs.version = JNI_VERSION_1_2;
attachArgs.name = "WinLauncher external command processing thread";
attachArgs.group = NULL;
- jvm->AttachCurrentThread((void**) &env, &attachArgs);
+ jvm->AttachCurrentThread((void**)&env, &attachArgs);
std::string processorClassName = LoadStdString(IDS_COMMAND_LINE_PROCESSOR_CLASS);
jclass processorClass = env->FindClass(processorClassName.c_str());
@@ -493,8 +493,8 @@
jmethodID processMethodID = env->GetStaticMethodID(processorClass, "processWindowsLauncherCommandLine", "(Ljava/lang/String;Ljava/lang/String;)V");
if (processMethodID)
{
- jstring jCurDir = env->NewString((const jchar *) curDir.c_str(), curDir.size());
- jstring jArgs = env->NewString((const jchar *) args.c_str(), args.size());
+ jstring jCurDir = env->NewString((const jchar *)curDir.c_str(), curDir.size());
+ jstring jArgs = env->NewString((const jchar *)args.c_str(), args.size());
env->CallStaticVoidMethod(processorClass, processMethodID, jCurDir, jArgs);
jthrowable exc = env->ExceptionOccurred();
if (exc)
@@ -509,7 +509,7 @@
DWORD WINAPI SingleInstanceThread(LPVOID args)
{
- while(true)
+ while (true)
{
WaitForSingleObject(hEvent, INFINITE);
if (terminating) break;
@@ -521,7 +521,7 @@
if (pos >= 0)
{
std::wstring curDir = command.substr(0, pos);
- std::wstring args = command.substr(pos+1);
+ std::wstring args = command.substr(pos + 1);
CallCommandLineProcessor(curDir, args);
}
@@ -534,7 +534,7 @@
void SendCommandLineToFirstInstance()
{
wchar_t curDir[_MAX_PATH];
- GetCurrentDirectoryW(_MAX_PATH-1, curDir);
+ GetCurrentDirectoryW(_MAX_PATH - 1, curDir);
std::wstring command(curDir);
command += _T("\n");
command += GetCommandLineW();
@@ -542,17 +542,17 @@
void *view = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (view)
{
- memcpy(view, command.c_str(), (command.size()+1) * sizeof(wchar_t));
+ memcpy(view, command.c_str(), (command.size() + 1) * sizeof(wchar_t));
UnmapViewOfFile(view);
}
- SetEvent(hEvent);
+ SetEvent(hEvent);
}
bool CheckSingleInstance()
{
char moduleFileName[_MAX_PATH];
- GetModuleFileNameA(NULL, moduleFileName, _MAX_PATH-1);
- for(char *p = moduleFileName; *p; p++)
+ GetModuleFileNameA(NULL, moduleFileName, _MAX_PATH - 1);
+ for (char *p = moduleFileName; *p; p++)
{
if (*p == ':' || *p == '\\') *p = '_';
}
@@ -564,7 +564,7 @@
hFileMapping = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, mappingName.c_str());
if (!hFileMapping)
{
- hFileMapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, FILE_MAPPING_SIZE,
+ hFileMapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, FILE_MAPPING_SIZE,
mappingName.c_str());
return true;
}
@@ -579,11 +579,11 @@
void DrawSplashImage(HWND hWnd)
{
- HBITMAP hSplashBitmap = (HBITMAP) GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ HBITMAP hSplashBitmap = (HBITMAP)GetWindowLongPtr(hWnd, GWLP_USERDATA);
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWnd, &ps);
HDC hMemDC = CreateCompatibleDC(hDC);
- HBITMAP hOldBmp = (HBITMAP) SelectObject(hMemDC, hSplashBitmap);
+ HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDC, hSplashBitmap);
BITMAP splashBitmap;
GetObject(hSplashBitmap, sizeof(splashBitmap), &splashBitmap);
BitBlt(hDC, 0, 0, splashBitmap.bmWidth, splashBitmap.bmHeight, hMemDC, 0, 0, SRCCOPY);
@@ -594,12 +594,12 @@
LRESULT CALLBACK SplashScreenWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
- switch(uMsg)
+ switch (uMsg)
{
case WM_PAINT:
DrawSplashImage(hWnd);
break;
- }
+ }
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
@@ -616,7 +616,7 @@
wcx.hInstance = hInst;
wcx.hIcon = 0;
wcx.hCursor = LoadCursor(NULL, IDC_WAIT);
- wcx.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
+ wcx.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
wcx.lpszMenuName = 0;
wcx.lpszClassName = splashClassName;
wcx.hIconSm = 0;
@@ -632,86 +632,120 @@
GetObject(hSplashBitmap, sizeof(splashBitmap), &splashBitmap);
int x = workArea.left + ((workArea.right - workArea.left) - splashBitmap.bmWidth) / 2;
int y = workArea.top + ((workArea.bottom - workArea.top) - splashBitmap.bmHeight) / 2;
-
+
HWND splashWindow = CreateWindowEx(WS_EX_TOOLWINDOW, splashClassName, splashClassName, WS_POPUP,
x, y, splashBitmap.bmWidth, splashBitmap.bmHeight, NULL, NULL, NULL, NULL);
- SetWindowLongPtr(splashWindow, GWLP_USERDATA, (LONG_PTR) hSplashBitmap);
+ SetWindowLongPtr(splashWindow, GWLP_USERDATA, (LONG_PTR)hSplashBitmap);
ShowWindow(splashWindow, SW_SHOW);
UpdateWindow(splashWindow);
return splashWindow;
}
+DWORD parentProcId;
+HANDLE parentProcHandle;
+
+BOOL IsParentProcessRunning(HANDLE hProcess)
+{
+ if (hProcess == NULL) return FALSE;
+ DWORD ret = WaitForSingleObject(hProcess, 0);
+ return ret == WAIT_TIMEOUT;
+}
+
BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
- static DWORD currentProcId = GetCurrentProcessId();
DWORD procId = 0;
GetWindowThreadProcessId(hWnd, &procId);
- if(currentProcId == procId)
+ if (parentProcId == procId)
{
- TCHAR className[_MAX_PATH];
- GetClassName(hWnd, className, _MAX_PATH-1);
- if (_tcscmp(className, splashClassName) != 0)
+ WINDOWINFO wi;
+ wi.cbSize = sizeof(WINDOWINFO);
+ GetWindowInfo(hWnd, &wi);
+ if ((wi.dwStyle & WS_VISIBLE) != 0)
{
- WINDOWINFO wi;
- wi.cbSize = sizeof(WINDOWINFO);
- GetWindowInfo(hWnd, &wi);
- if((wi.dwStyle & WS_VISIBLE) != 0)
- {
- HWND *phNewWindow = (HWND *) lParam;
- *phNewWindow = hWnd;
- return FALSE;
- }
+ HWND *phNewWindow = (HWND *)lParam;
+ *phNewWindow = hWnd;
+ return FALSE;
}
}
return TRUE;
}
-
-DWORD WINAPI SplashScreenThread(LPVOID args)
+DWORD WINAPI SplashScreen(HBITMAP hSplashBitmap)
{
- HBITMAP hSplashBitmap = static_cast<HBITMAP>(args);
RegisterSplashScreenWndClass();
HWND splashWindow = ShowSplashScreenWindow(hSplashBitmap);
-
MSG msg;
- while(true)
+ while (true)
{
- while (PeekMessage(&msg, splashWindow, 0, 0, PM_REMOVE))
+ while (PeekMessage(&msg, splashWindow, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(50);
HWND hNewWindow = NULL;
- EnumWindows(EnumWindowsProc, (LPARAM) &hNewWindow);
+ EnumWindows(EnumWindowsProc, (LPARAM)&hNewWindow);
if (hNewWindow)
{
BringWindowToTop(hNewWindow);
+ Sleep(100);
DeleteObject(hSplashBitmap);
DestroyWindow(splashWindow);
+ break;
}
+ if (!IsParentProcessRunning(parentProcHandle)) break;
}
return 0;
}
+void StartSplashProcess()
+{
+ TCHAR ownPath[_MAX_PATH];
+ TCHAR params[_MAX_PATH];
+
+ PROCESS_INFORMATION splashProcessInformation;
+ STARTUPINFO startupInfo;
+ memset(&splashProcessInformation, 0, sizeof(splashProcessInformation));
+ memset(&startupInfo, 0, sizeof(startupInfo));
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.dwFlags = STARTF_USESHOWWINDOW;
+ startupInfo.wShowWindow = SW_SHOW;
+
+ GetModuleFileName(NULL, ownPath, (sizeof(ownPath)));
+ _snwprintf(params, _MAX_PATH, _T("SPLASH %d"), GetCurrentProcessId());
+ if (CreateProcess(ownPath, params, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &splashProcessInformation))
+ {
+ CloseHandle(splashProcessInformation.hProcess);
+ CloseHandle(splashProcessInformation.hThread);
+ }
+}
+
int APIENTRY _tWinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPTSTR lpCmdLine,
- int nCmdShow)
+ HINSTANCE hPrevInstance,
+ LPTSTR lpCmdLine,
+ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
- UNREFERENCED_PARAMETER(lpCmdLine);
hInst = hInstance;
- if (!CheckSingleInstance()) return 1;
-
- HANDLE hSplashBitmap = static_cast<HBITMAP>(LoadImage(hInst, MAKEINTRESOURCE(IDB_SPLASH), IMAGE_BITMAP, 0, 0, 0));
- if (hSplashBitmap)
+ if (__argc == 2 && _wcsicmp(__wargv[0], _T("SPLASH")) == 0)
{
- CreateThread(NULL, 0, SplashScreenThread, hSplashBitmap, 0, NULL);
+ HBITMAP hSplashBitmap = static_cast<HBITMAP>(LoadImage(hInst, MAKEINTRESOURCE(IDB_SPLASH), IMAGE_BITMAP, 0, 0, 0));
+ if (hSplashBitmap)
+ {
+ parentProcId = _wtoi(__wargv[1]);
+ parentProcHandle = OpenProcess(SYNCHRONIZE, FALSE, parentProcId);
+ if (IsParentProcessRunning(parentProcHandle)) SplashScreen(hSplashBitmap);
+ }
+ CloseHandle(parentProcHandle);
+ return 0;
}
+ if (!CheckSingleInstance()) return 1;
+
+ if (wcsstr(lpCmdLine, _T("nosplash")) == NULL) StartSplashProcess();
+
if (!LocateJVM()) return 1;
if (!LoadVMOptions()) return 1;
if (!LoadJVMLibrary()) return 1;
@@ -731,4 +765,3 @@
return 0;
}
-
\ No newline at end of file
diff --git a/platform/bootstrap/src/com/intellij/ide/Bootstrap.java b/platform/bootstrap/src/com/intellij/ide/Bootstrap.java
index 847062c..00fab13 100644
--- a/platform/bootstrap/src/com/intellij/ide/Bootstrap.java
+++ b/platform/bootstrap/src/com/intellij/ide/Bootstrap.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/
package com.intellij.ide;
+import com.intellij.idea.Main;
import com.intellij.util.lang.UrlClassLoader;
import java.lang.reflect.Method;
@@ -24,13 +25,16 @@
*/
public class Bootstrap {
private static final String PLUGIN_MANAGER = "com.intellij.ide.plugins.PluginManager";
+
+ /** @deprecated use StartupUtil.NO_SPLASH if needed (to remove in 134.x) */
+ @SuppressWarnings({"UnusedDeclaration", "SpellCheckingInspection"})
public static final String NO_SPLASH = "nosplash";
private Bootstrap() { }
public static void main(String[] args, String mainClass, String methodName) throws Exception {
- UrlClassLoader newClassLoader = BootstrapClassLoaderUtil.initClassLoader(args.length == 0 || args.length == 1 &&
- NO_SPLASH.equals(args[0]));
+ boolean updatePlugins = !Main.isCommandLine();
+ UrlClassLoader newClassLoader = BootstrapClassLoaderUtil.initClassLoader(updatePlugins);
WindowsCommandLineProcessor.ourMirrorClass = Class.forName(WindowsCommandLineProcessor.class.getName(), true, newClassLoader);
diff --git a/platform/indexing-api/src/com/intellij/psi/search/SearchRequestCollector.java b/platform/indexing-api/src/com/intellij/psi/search/SearchRequestCollector.java
index f11b5fb..fef43be 100644
--- a/platform/indexing-api/src/com/intellij/psi/search/SearchRequestCollector.java
+++ b/platform/indexing-api/src/com/intellij/psi/search/SearchRequestCollector.java
@@ -16,6 +16,8 @@
package com.intellij.psi.search;
import com.intellij.codeInsight.ContainerProvider;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFileSystemItem;
@@ -82,9 +84,14 @@
searchWord(word, searchScope, searchContext, caseSensitive, getContainerName(searchTarget), processor);
}
- private static String getContainerName(@NotNull PsiElement target) {
- PsiElement container = getContainer(target);
- return container instanceof PsiNamedElement ? ((PsiNamedElement)container).getName() : null;
+ private static String getContainerName(@NotNull final PsiElement target) {
+ return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+ @Override
+ public String compute() {
+ PsiElement container = getContainer(target);
+ return container instanceof PsiNamedElement ? ((PsiNamedElement)container).getName() : null;
+ }
+ });
}
private static PsiElement getContainer(@NotNull PsiElement refElement) {
diff --git a/platform/indexing-impl/src/com/intellij/psi/stubs/StubProcessingHelperBase.java b/platform/indexing-impl/src/com/intellij/psi/stubs/StubProcessingHelperBase.java
index 27f7d10..9355f44 100644
--- a/platform/indexing-impl/src/com/intellij/psi/stubs/StubProcessingHelperBase.java
+++ b/platform/indexing-impl/src/com/intellij/psi/stubs/StubProcessingHelperBase.java
@@ -44,10 +44,15 @@
if (_psifile instanceof PsiFileWithStubSupport) {
psiFile = (PsiFileWithStubSupport)_psifile;
stubTree = psiFile.getStubTree();
- if (stubTree == null && psiFile instanceof PsiFileImpl) {
- BinaryFileStubBuilder stubBuilder = BinaryFileStubBuilders.INSTANCE.forFileType(psiFile.getFileType());
- if (stubBuilder == null) stubTree = ((PsiFileImpl)psiFile).calcStubTree();
- else customStubs = true;
+ if (stubTree == null && psiFile instanceof PsiFileImpl) {
+ IElementType contentElementType = ((PsiFileImpl)psiFile).getContentElementType();
+ if (contentElementType instanceof IStubFileElementType) {
+ stubTree = ((PsiFileImpl)psiFile).calcStubTree();
+ }
+ else {
+ customStubs = true;
+ assert BinaryFileStubBuilders.INSTANCE.forFileType(psiFile.getFileType()) != null;
+ }
}
}
}
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/group/ArrangementGroupingComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/group/ArrangementGroupingComponent.java
index c86f3ca..4bb84a6 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/group/ArrangementGroupingComponent.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/group/ArrangementGroupingComponent.java
@@ -101,7 +101,7 @@
myGroupingTypeToken.setListener(new ArrangementUiComponent.Listener() {
@Override
public void stateChanged() {
- myOrderTypeToken.setEnabled(myGroupingTypeToken.isEnabled());
+ myOrderTypeToken.setEnabled(myGroupingTypeToken.isSelected());
}
});
}
@@ -123,6 +123,7 @@
setBackground(UIUtil.getListBackground());
setBorder(IdeBorderFactory.createEmptyBorder(ArrangementConstants.VERTICAL_GAP));
+ setOpaque(!UIUtil.isUnderIntelliJLaF() && !UIUtil.isUnderNativeMacLookAndFeel() && !UIUtil.isUnderDarcula());
}
@Override
@@ -135,6 +136,10 @@
myRowIndexControl.setBaseLine(baseline);
}
}
+ if (UIUtil.isUnderIntelliJLaF() || UIUtil.isUnderDarcula() || UIUtil.isUnderNativeMacLookAndFeel()) {
+ g.setColor(getBackground());
+ g.fillRect(1, 1, getWidth() - 2, getHeight() - 2);
+ }
super.paintComponent(g);
}
diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FTManager.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FTManager.java
index b1b6cec..5e425be 100644
--- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FTManager.java
+++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FTManager.java
@@ -22,6 +22,7 @@
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
@@ -43,6 +44,7 @@
public static final String DEFAULT_TEMPLATE_EXTENSION = "ft";
public static final String TEMPLATE_EXTENSION_SUFFIX = "." + DEFAULT_TEMPLATE_EXTENSION;
public static final String CONTENT_ENCODING = CharsetToolkit.UTF8;
+ private static final String ENCODED_NAME_EXT_DELIMITER = "\u0F0Fext\u0F0F.";
private final String myName;
private final boolean myInternal;
@@ -119,8 +121,11 @@
// templateName must be non-qualified name, since previous lookup found nothing
for (FileTemplateBase t : getAllTemplates(false)) {
final String qName = t.getQualifiedName();
- if (qName.startsWith(templateName) && qName.charAt(templateName.length()) == '.') {
- return t;
+ if (qName.startsWith(templateName) && qName.length() > templateName.length()) {
+ String remainder = qName.substring(templateName.length());
+ if (remainder.startsWith(ENCODED_NAME_EXT_DELIMITER) || remainder.charAt(0) == '.') {
+ return t;
+ }
}
}
return null;
@@ -193,7 +198,7 @@
return bundled;
}
- void saveTemplates() {
+ public void saveTemplates() {
final File configRoot = getConfigRoot(true);
final File[] files = configRoot.listFiles();
@@ -262,7 +267,7 @@
* todo: review saving algorithm
*/
private static void saveTemplate(File parentDir, FileTemplateBase template, final String lineSeparator) throws IOException {
- final File templateFile = new File(parentDir, template.getName() + "." + template.getExtension());
+ final File templateFile = new File(parentDir, encodeFileName(template.getName(), template.getExtension()));
FileOutputStream fileOutputStream;
try {
@@ -310,4 +315,21 @@
return myName + " file template manager";
}
+ public static String encodeFileName(String templateName, String extension) {
+ String nameExtDelimiter = extension.contains(".") ? ENCODED_NAME_EXT_DELIMITER : ".";
+ return templateName + nameExtDelimiter + extension;
+ }
+
+ public static Pair<String,String> decodeFileName(String fileName) {
+ String name = fileName;
+ String ext = "";
+ String nameExtDelimiter = fileName.contains(ENCODED_NAME_EXT_DELIMITER) ? ENCODED_NAME_EXT_DELIMITER : ".";
+ int extIndex = fileName.lastIndexOf(nameExtDelimiter);
+ if (extIndex >= 0) {
+ name = fileName.substring(0, extIndex);
+ ext = fileName.substring(extIndex + nameExtDelimiter.length());
+ }
+ return new Pair<String,String>(name, ext);
+ }
+
}
diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateBase.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateBase.java
index a9f2374..73ee435 100644
--- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateBase.java
+++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateBase.java
@@ -54,7 +54,7 @@
}
public static String getQualifiedName(final String name, final String extension) {
- return name + "." + extension;
+ return FTManager.encodeFileName(name, extension);
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java
index 944cbc2..be3be30 100644
--- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java
+++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java
@@ -26,7 +26,6 @@
import com.intellij.lexer.Lexer;
import com.intellij.lexer.MergingLexerAdapter;
import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
@@ -305,11 +304,6 @@
myTemplate.setText(myTemplateEditor.getDocument().getText());
String name = myNameField.getText();
String extension = myExtensionField.getText();
- int lastDotIndex = extension.lastIndexOf(".");
- if (lastDotIndex >= 0) {
- name += extension.substring(0, lastDotIndex + 1);
- extension = extension.substring(lastDotIndex + 1);
- }
if (name.length() == 0 || !isValidFilename(name + "." + extension)) {
throw new ConfigurationException(IdeBundle.message("error.invalid.template.file.name.or.extension"));
}
diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java
index a067ed3..d3c230f 100644
--- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java
+++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java
@@ -22,6 +22,7 @@
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginDescriptor;
import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx;
+import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.lang.UrlClassLoader;
import org.jetbrains.annotations.NotNull;
@@ -191,7 +192,7 @@
}
}
- private void loadCustomizedContent(FTManager manager) {
+ void loadCustomizedContent(FTManager manager) {
final File configRoot = manager.getConfigRoot(false);
final File[] configFiles = configRoot.listFiles();
if (configFiles == null) {
@@ -226,9 +227,10 @@
}
}
- private void addTemplateFromFile(FTManager manager, String templateQName, File file) {
- final String extension = myTypeManager.getExtension(templateQName);
- templateQName = templateQName.substring(0, templateQName.length() - extension.length() - 1);
+ private static void addTemplateFromFile(FTManager manager, String fileName, File file) {
+ Pair<String,String> nameExt = FTManager.decodeFileName(fileName);
+ final String extension = nameExt.second;
+ final String templateQName = nameExt.first;
if (templateQName.length() == 0) {
return;
}
diff --git a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java
index db58f85..0e7ddb3 100644
--- a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java
+++ b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowManager.java
@@ -29,7 +29,7 @@
public abstract boolean canShowNotification(@NotNull String toolWindowId);
- public static ToolWindowManager getInstance(Project project){
+ public static ToolWindowManager getInstance(@NotNull Project project){
return project.getComponent(ToolWindowManager.class);
}
diff --git a/platform/platform-api/src/com/intellij/ui/ListCellRendererWrapper.java b/platform/platform-api/src/com/intellij/ui/ListCellRendererWrapper.java
index febb5b2..c4694d7 100644
--- a/platform/platform-api/src/com/intellij/ui/ListCellRendererWrapper.java
+++ b/platform/platform-api/src/com/intellij/ui/ListCellRendererWrapper.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,12 @@
*/
package com.intellij.ui;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
+import javax.swing.plaf.basic.BasicComboBoxRenderer;
import java.awt.*;
/**
@@ -42,8 +44,12 @@
@SuppressWarnings("UndesirableClassUsage")
public ListCellRendererWrapper() {
- myDefaultRenderer = new JComboBox().getRenderer();
- assert myDefaultRenderer != null : "LaF: " + UIManager.getLookAndFeel();
+ ListCellRenderer renderer = new JComboBox().getRenderer();
+ if (renderer == null) {
+ renderer = new BasicComboBoxRenderer();
+ Logger.getInstance(this.getClass()).error("LaF: " + UIManager.getLookAndFeel());
+ }
+ myDefaultRenderer = renderer;
}
public final Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
diff --git a/platform/platform-api/src/com/intellij/ui/components/JBViewport.java b/platform/platform-api/src/com/intellij/ui/components/JBViewport.java
index 4e98877..76ea93e 100644
--- a/platform/platform-api/src/com/intellij/ui/components/JBViewport.java
+++ b/platform/platform-api/src/com/intellij/ui/components/JBViewport.java
@@ -15,9 +15,11 @@
*/
package com.intellij.ui.components;
+import com.intellij.openapi.ui.TypingTarget;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ui.ComponentWithEmptyText;
import com.intellij.util.ui.StatusText;
+import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -26,9 +28,49 @@
import java.awt.event.ContainerListener;
public class JBViewport extends JViewport implements ZoomableViewport {
+ private static final ViewportLayout ourLayoutManager = new ViewportLayout() {
+
+ @Override
+ public void layoutContainer(Container parent) {
+ JBViewport viewport = (JBViewport)parent;
+ Component view = viewport.getView();
+ JBScrollPane scrollPane = UIUtil.getParentOfType(JBScrollPane.class, parent);
+ // do not force viewport size on editor component, e.g. EditorTextField and LanguageConsole
+ if (view == null || scrollPane == null || view instanceof TypingTarget) {
+ super.layoutContainer(parent);
+ return;
+ }
+
+ Dimension size = doSuperLayoutContainer(viewport);
+
+ Dimension visible = viewport.getExtentSize();
+ if (scrollPane.getHorizontalScrollBarPolicy() == ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER) {
+ size.width = visible.width;
+ }
+ if (scrollPane.getVerticalScrollBarPolicy() == ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER) {
+ size.height = visible.height;
+ }
+ viewport.setViewSize(size);
+ }
+
+ private Dimension doSuperLayoutContainer(JBViewport viewport) {
+ try {
+ viewport.mySaveTempViewSize = true;
+ super.layoutContainer(viewport);
+ }
+ finally {
+ viewport.mySaveTempViewSize = false;
+ }
+ return viewport.myTempViewSize;
+ }
+ };
+
private StatusText myEmptyText;
private ZoomingDelegate myZoomer;
+ private Dimension myTempViewSize;
+ private boolean mySaveTempViewSize;
+
public JBViewport() {
addContainerListener(new ContainerListener() {
@Override
@@ -52,6 +94,23 @@
}
@Override
+ protected LayoutManager createLayoutManager() {
+ return ourLayoutManager;
+ }
+
+ @Override
+ public void setViewSize(Dimension newSize) {
+ // only store newSize from ViewportLayout.layoutContainer
+ // if we're going to fix it the next moment in our layoutContainer code
+ if (mySaveTempViewSize) {
+ myTempViewSize = newSize;
+ }
+ else {
+ super.setViewSize(newSize);
+ }
+ }
+
+ @Override
public void paint(Graphics g) {
if (myZoomer != null && myZoomer.isActive()) {
myZoomer.paint(g);
diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java
index ef37fd9..0a49856 100644
--- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java
+++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
*/
package com.intellij.idea;
-import com.intellij.ide.Bootstrap;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.ConfigImportHelper;
@@ -47,7 +46,7 @@
* @author yole
*/
public class StartupUtil {
- @NonNls public static final String NO_SPLASH = Bootstrap.NO_SPLASH;
+ @NonNls public static final String NO_SPLASH = "nosplash";
private static SocketLock ourLock;
private static String myDefaultLAF;
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java
index 1a49ff2..6a0be3f 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java
@@ -82,11 +82,9 @@
}
}
finally {
- final Application app = ApplicationManager.getApplication();
- app.invokeLater(new DumbAwareRunnable() {
+ ApplicationManager.getApplication().invokeLater(new DumbAwareRunnable() {
@Override
public void run() {
- if (app.isDisposed()) return;
session.fireEvents(false);
}
}, modality);
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshSessionImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshSessionImpl.java
index d58cbb4..f7ad09a 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshSessionImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshSessionImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -161,7 +161,7 @@
public void fireEvents(boolean hasWriteAction) {
try {
- if (!iHaveEventsToFire) return;
+ if (!iHaveEventsToFire || ApplicationManager.getApplication().isDisposed()) return;
if (hasWriteAction) {
fireEventsInWriteAction();
diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties
index e1bbe4d..c9ac1ac 100644
--- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties
+++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties
@@ -491,3 +491,4 @@
dialog.edit.template.checkbox.xsl.text=XSL Text
highlight.imported.classes.chooser.title=Choose Imported Classes to Highlight
highlight.imported.members.chooser.title=Choose Imported Members to Highlight
+javadoc.resolved.value=Resolved value\:
\ No newline at end of file
diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml
index b2d0320..a8ef04f 100644
--- a/platform/platform-resources/src/META-INF/VcsExtensions.xml
+++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml
@@ -13,6 +13,8 @@
<projectService serviceImplementation="com.intellij.openapi.vcs.contentAnnotation.VcsContentAnnotationSettings"/>
<projectService serviceImplementation="com.intellij.openapi.diff.impl.settings.MergeToolSettings"/>
<projectService serviceImplementation="com.intellij.openapi.diff.impl.settings.DiffToolSettings"/>
+ <projectService serviceInterface="com.intellij.openapi.vcs.roots.VcsRootDetector"
+ serviceImplementation="com.intellij.openapi.vcs.roots.VcsRootDetectorImpl"/>
<selectInTarget implementation="com.intellij.openapi.vcs.changes.SelectInChangesViewTarget"/>
diff --git a/platform/platform-resources/src/brokenPlugins.txt b/platform/platform-resources/src/brokenPlugins.txt
new file mode 100644
index 0000000..5983a4d
--- /dev/null
+++ b/platform/platform-resources/src/brokenPlugins.txt
@@ -0,0 +1,13 @@
+// This file contains list of broken plugins.
+// Each line contains plugin ID and list of versions that are broken.
+// If plugin name or version contains a space you can quote it like in command line.
+
+NodeJS 133.74 133.50 133.373 133.293 133.260 133.195 133.162 133.134
+com.jetbrains.php 133.51 133.326 131.98 131.374 131.332 131.235 131.205 130.1639 130.1481 130.1176 129.91 129.814 129.672 129.362 127.67 127.100 126.334 123.66 122.875 121.62 121.390 121.215 121.12
+org.intellij.clojure 0.7.60
+org.intellij.scala 0.29.464 0.28.366 0.23.308
+org.jetbrains.plugins.ruby 6.0.0.20131207 6.0.0.20131121
+Karma 133.50
+com.jetbrains.lang.ejs 131.17 131.12
+com.jetbrains.twig 133.51 130.1639
+org.jetbrains.kannotator 0.2.420
\ No newline at end of file
diff --git a/platform/platform-tests/testSrc/com/intellij/ui/FinderRecursivePanelSelectionUpdateTest.java b/platform/platform-tests/testSrc/com/intellij/ui/FinderRecursivePanelSelectionUpdateTest.java
index 902067f..ce6c138 100644
--- a/platform/platform-tests/testSrc/com/intellij/ui/FinderRecursivePanelSelectionUpdateTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/ui/FinderRecursivePanelSelectionUpdateTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
public class FinderRecursivePanelSelectionUpdateTest extends PlatformTestCase {
- @Bombed(year = 2014, month = Calendar.JANUARY, day = 31, user = "Yann Cebron")
+ @Bombed(year = 2014, month = Calendar.MARCH, day = 1, user = "Yann Cebron")
public void testUpdate() throws InterruptedException {
StringFinderRecursivePanel panel_0 = new StringFinderRecursivePanel(getProject()) {
@NotNull
diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRootError.java b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRootError.java
index ada1125..3074d44 100644
--- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRootError.java
+++ b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRootError.java
@@ -23,61 +23,28 @@
* @author Kirill Likhodedov
* @see VcsRootChecker
*/
-public class VcsRootError {
+public interface VcsRootError {
- private final @NotNull Type myType;
- private final @NotNull String myMapping;
- private final @NotNull VcsKey myVcsKey;
-
- public enum Type {
+ enum Type {
EXTRA_MAPPING,
UNREGISTERED_ROOT
}
- public VcsRootError(@NotNull Type type, @NotNull String mapping, @NotNull String key) {
- myType = type;
- myMapping = mapping;
- myVcsKey = new VcsKey(key);
- }
-
+ /**
+ * @return type of mapping error
+ */
@NotNull
- public Type getType() {
- return myType;
- }
+ Type getType();
+ /**
+ * @return affected directory mapping string
+ */
@NotNull
- public String getMapping() {
- return myMapping;
- }
+ String getMapping();
+ /**
+ * @return vcsKey for affected mapping
+ */
@NotNull
- public VcsKey getVcsKey() {
- return myVcsKey;
- }
-
- @Override
- public String toString() {
- return String.format("VcsRootError{%s - %s}", myType, myMapping);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- VcsRootError error = (VcsRootError)o;
-
- if (!myMapping.equals(error.myMapping)) return false;
- if (myType != error.myType) return false;
-
- return true;
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- public int hashCode() {
- int result = myType != null ? myType.hashCode() : 0;
- result = 31 * result + myMapping.hashCode();
- return result;
- }
+ VcsKey getVcsKey();
}
diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRootFinder.java b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRootFinder.java
index b3b696e..473b722 100644
--- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRootFinder.java
+++ b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRootFinder.java
@@ -8,7 +8,7 @@
/**
* @author Denis Zhdanov
- * @since 7/18/13 3:53 PM
+ * @deprecated use {@link com.intellij.openapi.vcs.roots.VcsRootDetector} instead
*/
public interface VcsRootFinder {
diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/roots/VcsRootDetector.java b/platform/vcs-api/src/com/intellij/openapi/vcs/roots/VcsRootDetector.java
new file mode 100644
index 0000000..23a7e6b
--- /dev/null
+++ b/platform/vcs-api/src/com/intellij/openapi/vcs/roots/VcsRootDetector.java
@@ -0,0 +1,28 @@
+package com.intellij.openapi.vcs.roots;
+
+import com.intellij.openapi.vcs.VcsRoot;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+/**
+ * Interface for detecting VCS roots in the project.
+ *
+ * @author Nadya Zabrodina
+ */
+public interface VcsRootDetector {
+
+ /**
+ * Detect vcs roots for whole project
+ */
+ @NotNull
+ Collection<VcsRoot> detect();
+
+ /**
+ * Detect vcs roots for startDir
+ */
+ @NotNull
+ Collection<VcsRoot> detect(@Nullable VirtualFile startDir);
+}
diff --git a/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java b/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java
index 7093183..f49131c 100644
--- a/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java
+++ b/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java
@@ -22,6 +22,7 @@
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
@@ -38,6 +39,7 @@
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
+import com.intellij.openapi.vcs.roots.VcsRootDetector;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
import com.intellij.openapi.wm.StatusBar;
@@ -623,17 +625,21 @@
@NotNull
public static Collection<VcsDirectoryMapping> findRoots(@NotNull VirtualFile rootDir, @NotNull Project project)
- throws IllegalArgumentException
- {
+ throws IllegalArgumentException {
if (!rootDir.isDirectory()) {
throw new IllegalArgumentException(
"Can't find VCS at the target file system path. Reason: expected to find a directory there but it's not. The path: "
+ rootDir.getParent()
);
}
+ Collection<VcsRoot> roots = ServiceManager.getService(project, VcsRootDetector.class).detect(rootDir);
Collection<VcsDirectoryMapping> result = ContainerUtilRt.newArrayList();
- for (VcsRootFinder finder : VcsRootFinder.EP_NAME.getExtensions(project)) {
- result.addAll(finder.findRoots(rootDir));
+ for (VcsRoot vcsRoot : roots) {
+ VirtualFile vFile = vcsRoot.getPath();
+ AbstractVcs rootVcs = vcsRoot.getVcs();
+ if (rootVcs != null && vFile != null) {
+ result.add(new VcsDirectoryMapping(vFile.getPath(), rootVcs.getName()));
+ }
}
return result;
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsRootErrorImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsRootErrorImpl.java
new file mode 100644
index 0000000..d6d3f63
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsRootErrorImpl.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2013 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.vcs;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Nadya Zabrodina
+ */
+public class VcsRootErrorImpl implements VcsRootError {
+
+ private final @NotNull Type myType;
+ private final @NotNull String myMapping;
+ private final @NotNull VcsKey myVcsKey;
+
+
+ public VcsRootErrorImpl(@NotNull Type type, @NotNull String mapping, @NotNull String key) {
+ myType = type;
+ myMapping = mapping;
+ myVcsKey = new VcsKey(key);
+ }
+
+ @NotNull
+ public Type getType() {
+ return myType;
+ }
+
+ @NotNull
+ public String getMapping() {
+ return myMapping;
+ }
+
+ @NotNull
+ public VcsKey getVcsKey() {
+ return myVcsKey;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("VcsRootError{%s - %s}", myType, myMapping);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ VcsRootError error = (VcsRootError)o;
+
+ if (!myMapping.equals(error.getMapping())) return false;
+ if (myType != error.getType()) return false;
+
+ return true;
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ @Override
+ public int hashCode() {
+ int result = myType != null ? myType.hashCode() : 0;
+ result = 31 * result + myMapping.hashCode();
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootDetectInfo.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootDetectInfo.java
deleted file mode 100644
index eae6956..0000000
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootDetectInfo.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.intellij.openapi.vcs.roots;
-
-import com.intellij.openapi.vcs.VcsRoot;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * @author Nadya Zabrodina
- */
-public class VcsRootDetectInfo {
-
- private final @NotNull Collection<VcsRoot> myRoots;
- private final boolean myBelow;
-
- /**
- * @param roots Vcs roots important for the project.
- * @param below Pass true to indicate that the project dir is below Vcs dir,
- */
- public VcsRootDetectInfo(@NotNull Collection<VcsRoot> roots, boolean below) {
- myRoots = new ArrayList<VcsRoot>(roots);
- myBelow = below;
- }
-
- public boolean empty() {
- return myRoots.isEmpty();
- }
-
- @NotNull
- public Collection<VcsRoot> getRoots() {
- return new ArrayList<VcsRoot>(myRoots);
- }
-
- /**
- * Below implies totally under Vcs.
- *
- * @return true if the uppermost interesting Vcs root is above the project dir,
- * false if all vcs internal directories are immediately under the project dir or deeper.
- */
- public boolean projectIsBelowVcs() {
- return myBelow;
- }
-}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootDetector.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootDetectorImpl.java
similarity index 69%
rename from platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootDetector.java
rename to platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootDetectorImpl.java
index d298baa..8b600cb 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootDetector.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootDetectorImpl.java
@@ -1,3 +1,18 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.intellij.openapi.vcs.roots;
import com.intellij.openapi.extensions.Extensions;
@@ -16,48 +31,49 @@
/**
* @author Nadya Zabrodina
*/
-public class VcsRootDetector {
+public class VcsRootDetectorImpl implements VcsRootDetector {
private static final int MAXIMUM_SCAN_DEPTH = 2;
@NotNull private final Project myProject;
@NotNull private final ProjectRootManager myProjectManager;
@NotNull private final ProjectLevelVcsManager myVcsManager;
+ @NotNull private final VcsRootChecker[] myCheckers;
- public VcsRootDetector(@NotNull Project project) {
+ public VcsRootDetectorImpl(@NotNull Project project,
+ @NotNull ProjectRootManager projectRootManager,
+ @NotNull ProjectLevelVcsManager projectLevelVcsManager) {
myProject = project;
- myProjectManager = ProjectRootManager.getInstance(project);
- myVcsManager = ProjectLevelVcsManager.getInstance(project);
+ myProjectManager = projectRootManager;
+ myVcsManager = projectLevelVcsManager;
+ myCheckers = Extensions.getExtensions(VcsRootChecker.EXTENSION_POINT_NAME);
}
@NotNull
- public VcsRootDetectInfo detect() {
+ public Collection<VcsRoot> detect() {
return detect(myProject.getBaseDir());
}
@NotNull
- public VcsRootDetectInfo detect(@Nullable VirtualFile startDir) {
- if (startDir == null) {
- return new VcsRootDetectInfo(Collections.<VcsRoot>emptyList(), false);
+ public Collection<VcsRoot> detect(@Nullable VirtualFile startDir) {
+ if (startDir == null || myCheckers.length == 0) {
+ return Collections.emptyList();
}
final Set<VcsRoot> roots = scanForRootsInsideDir(startDir);
roots.addAll(scanForRootsInContentRoots());
for (VcsRoot root : roots) {
if (startDir.equals(root.getPath())) {
- return new VcsRootDetectInfo(roots, false);
+ return roots;
}
}
List<VcsRoot> rootsAbove = scanForSingleRootAboveDir(startDir);
- if (!rootsAbove.isEmpty()) {
- roots.addAll(rootsAbove);
- return new VcsRootDetectInfo(roots, true);
- }
- return new VcsRootDetectInfo(roots, false);
+ roots.addAll(rootsAbove);
+ return roots;
}
@NotNull
private Set<VcsRoot> scanForRootsInContentRoots() {
- Set<VcsRoot> gitRoots = new HashSet<VcsRoot>();
+ Set<VcsRoot> vcsRoots = new HashSet<VcsRoot>();
VirtualFile[] roots = myProjectManager.getContentRoots();
for (VirtualFile contentRoot : roots) {
@@ -72,9 +88,9 @@
List<VcsRoot> rootsAbove = scanForSingleRootAboveDir(contentRoot);
rootsInsideRoot.addAll(rootsAbove);
}
- gitRoots.addAll(rootsInsideRoot);
+ vcsRoots.addAll(rootsInsideRoot);
}
- return gitRoots;
+ return vcsRoots;
}
@NotNull
@@ -126,9 +142,8 @@
@NotNull
private List<AbstractVcs> getVcsListFor(@NotNull VirtualFile dir) {
- VcsRootChecker[] checkers = Extensions.getExtensions(VcsRootChecker.EXTENSION_POINT_NAME);
List<AbstractVcs> vcsList = new ArrayList<AbstractVcs>();
- for (VcsRootChecker checker : checkers) {
+ for (VcsRootChecker checker : myCheckers) {
if (checker.isRoot(dir.getPath())) {
vcsList.add(myVcsManager.findVcsByName(checker.getSupportedVcs().getName()));
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootErrorsFinder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootErrorsFinder.java
index 0c5bcc5..2769b3c 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootErrorsFinder.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/roots/VcsRootErrorsFinder.java
@@ -1,5 +1,6 @@
package com.intellij.openapi.vcs.roots;
+import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
@@ -30,7 +31,7 @@
@NotNull
public Collection<VcsRootError> find() {
List<VcsDirectoryMapping> mappings = myVcsManager.getDirectoryMappings();
- Collection<VcsRoot> vcsRoots = new VcsRootDetector(myProject).detect().getRoots();
+ Collection<VcsRoot> vcsRoots = ServiceManager.getService(myProject, VcsRootDetector.class).detect();
Collection<VcsRootError> errors = new ArrayList<VcsRootError>();
errors.addAll(findExtraMappings(mappings));
@@ -50,7 +51,7 @@
}
String vcsPath = virtualFileFromRoot.getPath();
if (!mappedPaths.contains(vcsPath) && root.getVcs() != null) {
- errors.add(new VcsRootError(VcsRootError.Type.UNREGISTERED_ROOT, vcsPath, root.getVcs().getName()));
+ errors.add(new VcsRootErrorImpl(VcsRootError.Type.UNREGISTERED_ROOT, vcsPath, root.getVcs().getName()));
}
}
return errors;
@@ -65,13 +66,13 @@
}
if (mapping.isDefaultMapping()) {
if (!isRoot(mapping)) {
- errors.add(new VcsRootError(VcsRootError.Type.EXTRA_MAPPING, VcsDirectoryMapping.PROJECT_CONSTANT, mapping.getVcs()));
+ errors.add(new VcsRootErrorImpl(VcsRootError.Type.EXTRA_MAPPING, VcsDirectoryMapping.PROJECT_CONSTANT, mapping.getVcs()));
}
}
else {
String mappedPath = mapping.systemIndependentPath();
if (!isRoot(mapping)) {
- errors.add(new VcsRootError(VcsRootError.Type.EXTRA_MAPPING, mappedPath, mapping.getVcs()));
+ errors.add(new VcsRootErrorImpl(VcsRootError.Type.EXTRA_MAPPING, mappedPath, mapping.getVcs()));
}
}
}
diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootConfiguration.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootConfiguration.java
new file mode 100644
index 0000000..d3ac4b3
--- /dev/null
+++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootConfiguration.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2000-2013 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.vcs.roots;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * @author Nadya Zabrodina
+ */
+public class VcsRootConfiguration {
+
+ @NotNull private Collection<String> myMockRoots;
+ @NotNull private Collection<String> myContentRoots;
+ @NotNull private Collection<String> myRoots;
+ @NotNull private Collection<String> myUnregErrors;
+ @NotNull private Collection<String> myExtraErrors;
+
+
+ public VcsRootConfiguration() {
+ myMockRoots = Collections.emptyList();
+ myRoots = Collections.emptyList();
+ myContentRoots = Collections.emptyList();
+ myUnregErrors = Collections.emptyList();
+ myExtraErrors = Collections.emptyList();
+ }
+
+ public VcsRootConfiguration mock(@NotNull Collection<String> mockRoots) {
+ myMockRoots = mockRoots;
+ return this;
+ }
+
+ public VcsRootConfiguration roots(@NotNull Collection<String> roots) {
+ myRoots = roots;
+ return this;
+ }
+
+ public VcsRootConfiguration contentRoots(@NotNull Collection<String> contentRoots) {
+ myContentRoots = contentRoots;
+ return this;
+ }
+
+ public VcsRootConfiguration unregErrors(@NotNull Collection<String> unregErrors) {
+ myUnregErrors = unregErrors;
+ return this;
+ }
+
+ public VcsRootConfiguration extraErrors(@NotNull Collection<String> extraErrors) {
+ myExtraErrors = extraErrors;
+ return this;
+ }
+
+ @NotNull
+ public Collection<String> getMockRoots() {
+ return myMockRoots;
+ }
+
+ @NotNull
+ public Collection<String> getContentRoots() {
+ return myContentRoots;
+ }
+
+ @NotNull
+ public Collection<String> getRoots() {
+ return myRoots;
+ }
+
+ @NotNull
+ public Collection<String> getUnregErrors() {
+ return myUnregErrors;
+ }
+
+ @NotNull
+ public Collection<String> getExtraErrors() {
+ return myExtraErrors;
+ }
+}
diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootDetectorTest.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootDetectorTest.java
index 8a5e862..aa62381 100644
--- a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootDetectorTest.java
+++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootDetectorTest.java
@@ -13,8 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.intellij.openapi.vcs.roots;
+import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.io.FileUtil;
@@ -28,7 +30,9 @@
import java.io.File;
import java.io.IOException;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import static com.intellij.openapi.vcs.Executor.cd;
import static com.intellij.openapi.vcs.Executor.mkdir;
@@ -37,138 +41,107 @@
/**
* @author Nadya Zabrodina
*/
+
public class VcsRootDetectorTest extends VcsRootPlatformTest {
public void testNoRootsInProject() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Collections.<String>emptyList());
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, null, Collections.<String>emptyList());
+ doTest(new VcsRootConfiguration(), null, Collections.<String>emptyList());
}
public void testProjectUnderSingleMockRoot() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList("."));
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, myProjectRoot, Arrays.asList("."));
+ doTest(new VcsRootConfiguration().mock(Arrays.asList(".")), myProjectRoot, Arrays.asList("."));
}
public void testProjectWithMockRootUnderIt() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList("community"));
- map.put("content_roots", Collections.<String>emptyList());
cd(myProjectRoot);
mkdir("src");
mkdir(".idea");
- doTest(map, myProjectRoot, Arrays.asList("community"));
+ doTest(new VcsRootConfiguration().mock(Arrays.asList("community")), myProjectRoot, Arrays.asList("community"));
}
public void testProjectWithAllSubdirsUnderMockRootShouldStillBeNotFullyControlled() throws IOException {
String[] dirNames = {".idea", "src", "community"};
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(dirNames));
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, myProjectRoot, Arrays.asList(dirNames));
+ doTest(new VcsRootConfiguration().mock(Arrays.asList(dirNames)), myProjectRoot, Arrays.asList(dirNames));
}
public void testProjectUnderVcsAboveIt() throws IOException {
String subdir = "insideRepo";
cd(myRepository);
mkdir(subdir);
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(myRepository.getName()));
- map.put("content_roots", Collections.<String>emptyList());
VirtualFile vfile = myRepository.findChild(subdir);
- doTest(map, vfile, Arrays.asList(myRepository.getName())
+ doTest(new VcsRootConfiguration().mock(Arrays.asList(myRepository.getName())), vfile, Arrays.asList(myRepository.getName())
);
}
public void testIDEAProject() throws IOException {
String[] names = {"community", "contrib", "."};
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(names));
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, myProjectRoot, Arrays.asList(names));
+ doTest(new VcsRootConfiguration().mock(Arrays.asList(names)), myProjectRoot, Arrays.asList(names));
}
public void testOneAboveAndOneUnder() throws IOException {
String[] names = {myRepository.getName() + "/community", "."};
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(names));
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, myRepository, Arrays.asList(names));
+ doTest(new VcsRootConfiguration().mock(Arrays.asList(names)), myRepository, Arrays.asList(names));
}
public void testOneAboveAndOneForProjectShouldShowOnlyProjectRoot() throws IOException {
String[] names = {myRepository.getName(), "."};
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(names));
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, myRepository, Arrays.asList(myRepository.getName()));
+ doTest(new VcsRootConfiguration().mock(Arrays.asList(names)), myRepository, Arrays.asList(myRepository.getName()));
}
public void testOneAboveAndSeveralUnderProject() throws IOException {
String[] names = {".", myRepository.getName() + "/community", myRepository.getName() + "/contrib"};
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(names));
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, myRepository, Arrays.asList(names));
+ doTest(new VcsRootConfiguration().mock(Arrays.asList(names)), myRepository, Arrays.asList(names));
}
public void testMultipleAboveShouldBeDetectedAsOneAbove() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(".", myRepository.getName()));
- map.put("content_roots", Collections.<String>emptyList());
String subdir = "insideRepo";
cd(myRepository);
mkdir(subdir);
VirtualFile vfile = myRepository.findChild(subdir);
- doTest(map, vfile, Arrays.asList(myRepository.getName()));
+ doTest(new VcsRootConfiguration().mock(Arrays.asList(".", myRepository.getName())), vfile, Arrays.asList(myRepository.getName()));
}
public void testUnrelatedRootShouldNotBeDetected() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList("another"));
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, myRepository, Collections.<String>emptyList());
+ doTest(new VcsRootConfiguration().mock(Arrays.asList("another")), myRepository, Collections.<String>emptyList());
}
public void testLinkedSourceRootAloneShouldBeDetected() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList("linked_root"));
- map.put("content_roots", Arrays.asList("linked_root"));
- doTest(map, myRepository, Arrays.asList("linked_root"));
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList("linked_root"))
+ .contentRoots(Arrays.asList("linked_root"));
+ doTest(vcsRootConfiguration, myRepository, Arrays.asList("linked_root"));
}
public void testLinkedSourceRootAndProjectRootShouldBeDetected() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(".", "linked_root"));
- map.put("content_roots", Arrays.asList("linked_root"));
- doTest(map, myProjectRoot, Arrays.asList(".", "linked_root"));
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList(".", "linked_root"))
+ .contentRoots(Arrays.asList("linked_root"));
+ doTest(vcsRootConfiguration, myProjectRoot, Arrays.asList(".", "linked_root"));
}
public void testLinkedSourceBelowMockRoot() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(".", "linked_root"));
- map.put("content_roots", Arrays.asList("linked_root/src"));
- doTest(map, myProjectRoot, Arrays.asList(".", "linked_root"));
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().contentRoots(Arrays.asList("linked_root/src"))
+ .mock(Arrays.asList(".", "linked_root"));
+ doTest(vcsRootConfiguration, myProjectRoot, Arrays.asList(".", "linked_root"));
}
// This is a test of performance optimization via limitation: don't scan deep though the whole VFS, i.e. don't detect deep roots
public void testDontScanDeeperThan2LevelsBelowAContentRoot() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList("community", "content_root/lev1/lev2", "content_root2/lev1/lev2/lev3"));
- map.put("content_roots", Arrays.asList("content_root"));
- doTest(map, myProjectRoot, Arrays.asList("community", "content_root/lev1/lev2"));
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList("community", "content_root/lev1/lev2", "content_root2/lev1/lev2/lev3"))
+ .contentRoots(Arrays.asList("content_root"));
+ doTest(vcsRootConfiguration,
+ myProjectRoot, Arrays.asList("community", "content_root/lev1/lev2"));
}
- void assertRoots(Collection<String> expectedRelativePaths, Collection<String> actual) {
+ void assertRoots(@NotNull Collection<String> expectedRelativePaths, @NotNull Collection<String> actual) {
VcsTestUtil.assertEqualCollections(actual, toAbsolute(expectedRelativePaths, myProject));
}
@NotNull
- public static Collection<String> toAbsolute(Collection<String> relPaths, final Project project) {
+ public static Collection<String> toAbsolute(@NotNull Collection<String> relPaths, @NotNull final Project project) {
return ContainerUtil.map(relPaths, new Function<String, String>() {
@Override
public String fun(String s) {
@@ -197,24 +170,24 @@
}
@NotNull
- private VcsRootDetectInfo detect(@Nullable VirtualFile startDir) {
- return new VcsRootDetector(myProject).detect(startDir);
+ private Collection<VcsRoot> detect(@Nullable VirtualFile startDir) {
+ return ServiceManager.getService(myProject, VcsRootDetector.class).detect(startDir);
}
- public void doTest(@NotNull Map<String, Collection<String>> map,
+ public void doTest(@NotNull VcsRootConfiguration vcsRootConfiguration,
@Nullable VirtualFile startDir,
@NotNull Collection<String> expectedPaths)
throws IOException {
- initProject(map.get("mock"), Collections.<String>emptyList(), map.get("content_roots"));
-
- VcsRootDetectInfo info = detect(startDir);
+ initProject(vcsRootConfiguration);
+ Collection<VcsRoot> vcsRoots = detect(startDir);
assertRoots(expectedPaths, getPaths(
- ContainerUtil.filter(info.getRoots(), new Condition<VcsRoot>() {
+ ContainerUtil.filter(vcsRoots, new Condition<VcsRoot>() {
@Override
public boolean value(VcsRoot root) {
assert root.getVcs() != null;
return root.getVcs().getKeyInstanceMethod().equals(myVcs.getKeyInstanceMethod());
}
- })));
+ })
+ ));
}
}
diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootErrorsFinderTest.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootErrorsFinderTest.java
index 80a9ce9..cec34c8 100644
--- a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootErrorsFinderTest.java
+++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootErrorsFinderTest.java
@@ -18,12 +18,15 @@
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vcs.VcsDirectoryMapping;
import com.intellij.openapi.vcs.VcsRootError;
+import com.intellij.openapi.vcs.VcsRootErrorImpl;
import com.intellij.openapi.vcs.VcsTestUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
/**
@@ -39,187 +42,143 @@
}
public void testNoRootsThenNoErrors() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Collections.<String>emptyList());
- map.put("roots", Collections.<String>emptyList());
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, Collections.<String, Collection<String>>emptyMap());
+ doTest(new VcsRootConfiguration());
}
public void testSameOneRootInBothThenNoErrors() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList("."));
- map.put("roots", Arrays.asList("."));
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, Collections.<String, Collection<String>>emptyMap());
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList("."))
+ .roots(Arrays.asList("."));
+ doTest(vcsRootConfiguration);
}
public void testSameTwoRootsInBothThenNoErrors() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(".", "community"));
- map.put("roots", Arrays.asList(".", "community"));
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, Collections.<String, Collection<String>>emptyMap());
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList(".", "community"))
+ .roots(Arrays.asList(".", "community"));
+ doTest(vcsRootConfiguration);
}
public void testOneMockRootNoVCSRootsThenError() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList("."));
- map.put("roots", Collections.<String>emptyList());
- map.put("content_roots", Collections.<String>emptyList());
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("unreg", Arrays.asList("."));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList("."))
+ .unregErrors(Arrays.asList("."));
+ doTest(vcsRootConfiguration);
}
public void testOneVCSRootNoMockRootsThenError() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("roots", Arrays.asList("."));
- map.put("mock", Collections.<String>emptyList());
- map.put("content_roots", Collections.<String>emptyList());
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("extra", Arrays.asList("."));
- doTest(map, errorsMap);
+
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().roots(Arrays.asList("."))
+ .extraErrors(Arrays.asList("."));
+ doTest(vcsRootConfiguration);
}
+
public void testOneRootButDifferentThenTwoErrors() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList("."));
- map.put("roots", Arrays.asList("community"));
- map.put("content_roots", Collections.<String>emptyList());
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("extra", Arrays.asList("community"));
- errorsMap.put("unreg", Arrays.asList("."));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList("."))
+ .roots(Arrays.asList("community"))
+ .unregErrors(Arrays.asList(".")).extraErrors(Arrays.asList("community"));
+ doTest(vcsRootConfiguration);
}
public void testTwoRootsOneMatchingOneDifferentThenTwoErrors() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(".", "community"));
- map.put("roots", Arrays.asList(".", "contrib"));
- map.put("content_roots", Collections.<String>emptyList());
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("extra", Arrays.asList("contrib"));
- errorsMap.put("unreg", Arrays.asList("community"));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList(".", "community"))
+ .roots(Arrays.asList(".", "contrib"))
+ .unregErrors(Arrays.asList("community")).extraErrors(Arrays.asList("contrib"));
+ doTest(vcsRootConfiguration);
}
public void testTwoRootsInMockRootOneMatchingInVCSThenError() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(".", "community"));
- map.put("roots", Arrays.asList("."));
- map.put("content_roots", Collections.<String>emptyList());
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("unreg", Arrays.asList("community"));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList(".", "community"))
+ .roots(Arrays.asList("."))
+ .unregErrors(Arrays.asList("community"));
+ doTest(vcsRootConfiguration);
}
public void testTwoRootsBothNotMatchingThenFourErrors() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(".", "community"));
- map.put("roots", Arrays.asList("another", "contrib"));
- map.put("content_roots", Collections.<String>emptyList());
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("extra", Arrays.asList("contrib", "another"));
- errorsMap.put("unreg", Arrays.asList("community", "."));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList(".", "community"))
+ .roots(Arrays.asList("another", "contrib"))
+ .unregErrors(Arrays.asList("community", ".")).extraErrors(Arrays.asList("contrib", "another"));
+ doTest(vcsRootConfiguration);
}
public void testProjectRootNoMockRootsThenErrorAboutExtraRoot() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Collections.<String>emptyList());
- map.put("roots", Arrays.asList(PROJECT));
- map.put("content_roots", Collections.<String>emptyList());
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("extra", Arrays.asList(PROJECT));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration()
+ .roots(Arrays.asList(PROJECT))
+ .extraErrors(Arrays.asList(PROJECT));
+ doTest(vcsRootConfiguration);
}
public void testProjectRootFullUnderMockRootThenCorrect() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList("."));
- map.put("roots", Arrays.asList(".", PROJECT));
- map.put("content_roots", Collections.<String>emptyList());
- doTest(map, Collections.<String, Collection<String>>emptyMap());
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList("."))
+ .roots(Arrays.asList(PROJECT));
+ doTest(vcsRootConfiguration);
}
public void testProjectRootMockRootForAContentRootBelowProjectThenError() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList("content_root"));
- map.put("roots", Arrays.asList(PROJECT));
- map.put("content_roots", Arrays.asList("content_root"));
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("unreg", Arrays.asList("content_root"));
- errorsMap.put("extra", Arrays.asList(PROJECT));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList("content_root"))
+ .contentRoots(Arrays.asList("content_root")).roots(Arrays.asList(PROJECT))
+ .unregErrors(Arrays.asList("content_root")).extraErrors(Arrays.asList(PROJECT));
+ doTest(vcsRootConfiguration);
}
public void testProjectRootMockRootBelowProjectFolderNotInAContentRootThenUnregisteredRootError() throws IOException {
// this is to be fixed: auto-detection of MockRoot repositories in subfolders for the <Project> mapping
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList("community"));
- map.put("roots", Arrays.asList(PROJECT));
- map.put("content_roots", Arrays.asList("."));
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("unreg", Arrays.asList("community"));
- errorsMap.put("extra", Arrays.asList(PROJECT));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList("community"))
+ .contentRoots(Arrays.asList(".")).roots(Arrays.asList(PROJECT))
+ .unregErrors(Arrays.asList("community")).extraErrors(Arrays.asList(PROJECT));
+ doTest(vcsRootConfiguration);
}
public void testProjectRootMockRootForFullProjectContentRootLinkedSourceFolderBelowProjectThenErrors() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(".", "content_root", "../linked_source_root", "folder"));
- map.put("roots", Arrays.asList(PROJECT));
- map.put("content_roots", Arrays.asList(".", "content_root", "../linked_source_root"));
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("unreg", Arrays.asList("content_root", "../linked_source_root", "folder"));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList(".", "content_root", "../linked_source_root", "folder"))
+ .roots(Arrays.asList(PROJECT))
+ .contentRoots(Arrays.asList(".", "content_root", "../linked_source_root"))
+ .unregErrors(Arrays.asList("content_root", "../linked_source_root", "folder"));
+ doTest(vcsRootConfiguration);
}
public void testProjectRootForFolderMockRootForFullProjectContentRootLinkedSourceFolderBelowProjectThenErrors() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(".", "content_root", "../linked_source_root", "folder"));
- map.put("roots", Arrays.asList(PROJECT, "folder"));
- map.put("content_roots", Arrays.asList(".", "content_root", "../linked_source_root"));
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("unreg", Arrays.asList("content_root", "../linked_source_root"));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList(".", "content_root", "../linked_source_root", "folder"))
+ .roots(Arrays.asList(PROJECT, "folder"))
+ .contentRoots(Arrays.asList(".", "content_root", "../linked_source_root"))
+ .unregErrors(Arrays.asList("content_root", "../linked_source_root"));
+ doTest(vcsRootConfiguration);
}
public void testProjectRootMockRootLikeInIDEAProjectThenError() throws IOException {
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(".", "community", "contrib"));
- map.put("roots", Arrays.asList(PROJECT));
- map.put("content_roots", Arrays.asList(".", "community", "contrib"));
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("unreg", Arrays.asList("community", "contrib"));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList(".", "community", "contrib")).roots(Arrays.asList(PROJECT))
+ .contentRoots(Arrays.asList(".", "community", "contrib")).unregErrors(Arrays.asList("community", "contrib"));
+ doTest(vcsRootConfiguration);
}
public void testRealMockRootRootDeeperThanThreeLevelsShouldBeDetected() throws IOException {
-
- Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
- map.put("mock", Arrays.asList(".", "community", "contrib", "community/level1/level2/level3"));
- map.put("roots", Arrays.asList(PROJECT, "community/level1/level2/level3"));
- map.put("content_roots", Arrays.asList(".", "community", "contrib"));
- Map<String, Collection<String>> errorsMap = new HashMap<String, Collection<String>>();
- errorsMap.put("unreg", Arrays.asList("community", "contrib"));
- doTest(map, errorsMap);
+ VcsRootConfiguration vcsRootConfiguration =
+ new VcsRootConfiguration().mock(Arrays.asList(".", "community", "contrib", "community/level1/level2/level3"))
+ .contentRoots(Arrays.asList(".", "community", "contrib")).roots(Arrays.asList(PROJECT, "community/level1/level2/level3"))
+ .unregErrors(Arrays.asList("community", "contrib"));
+ doTest(vcsRootConfiguration);
}
- private void doTest(@NotNull Map<String, Collection<String>> map, @NotNull Map<String, Collection<String>> errors) throws IOException {
- initProject(map.get("mock"), Collections.<String>emptyList(), map.get("content_roots"));
- addVcsRoots(map.get("roots"));
+ private void doTest(@NotNull VcsRootConfiguration vcsRootConfiguration) throws IOException {
+ initProject(vcsRootConfiguration);
+ addVcsRoots(vcsRootConfiguration.getRoots());
Collection<VcsRootError> expected = new ArrayList<VcsRootError>();
- Collection<String> unregPaths = errors.get("unreg");
- Collection<String> extraPaths = errors.get("extra");
- if (unregPaths != null) {
- expected.addAll(unregAll(unregPaths));
- }
- if (extraPaths != null) {
- expected.addAll(extraAll(extraPaths));
- }
+ expected.addAll(unregAll(vcsRootConfiguration.getUnregErrors()));
+ expected.addAll(extraAll(vcsRootConfiguration.getExtraErrors()));
Collection<VcsRootError> actual = ContainerUtil.filter(new VcsRootErrorsFinder(myProject).find(), new Condition<VcsRootError>() {
@Override
public boolean value(VcsRootError error) {
@@ -261,12 +220,12 @@
@NotNull
VcsRootError unreg(@NotNull String path) {
- return new VcsRootError(VcsRootError.Type.UNREGISTERED_ROOT, VcsTestUtil.toAbsolute(path, myProject), myVcsName);
+ return new VcsRootErrorImpl(VcsRootError.Type.UNREGISTERED_ROOT, VcsTestUtil.toAbsolute(path, myProject), myVcsName);
}
@NotNull
VcsRootError extra(@NotNull String path) {
- return new VcsRootError(VcsRootError.Type.EXTRA_MAPPING, PROJECT.equals(path) ? PROJECT : VcsTestUtil.toAbsolute(path, myProject),
- myVcsName);
+ return new VcsRootErrorImpl(VcsRootError.Type.EXTRA_MAPPING, PROJECT.equals(path) ? PROJECT : VcsTestUtil.toAbsolute(path, myProject),
+ myVcsName);
}
}
diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootPlatformTest.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootPlatformTest.java
index 5bf8164..407903b 100644
--- a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootPlatformTest.java
+++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootPlatformTest.java
@@ -141,12 +141,10 @@
*
* @param mockRoots path to actual .mock roots, relative to the project dir.
*/
- public void initProject(@NotNull Collection<String> mockRoots,
- @NotNull Collection<String> projectStructure,
- @NotNull Collection<String> contentRoots)
+ public void initProject(@NotNull VcsRootConfiguration vcsRootConfiguration)
throws IOException {
- createDirs(mockRoots);
- createProjectStructure(myProject, projectStructure);
+ createDirs(vcsRootConfiguration.getMockRoots());
+ Collection<String> contentRoots = vcsRootConfiguration.getContentRoots();
createProjectStructure(myProject, contentRoots);
if (!contentRoots.isEmpty()) {
for (String root : contentRoots) {
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java
index d0f47ec..3bcd247 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java
@@ -43,10 +43,10 @@
@NotNull
private static TimedVcsCommit findLatestCommit(@NotNull Set<TimedVcsCommit> commits) {
- long maxTimeStamp = 0;
+ long maxTimeStamp = Long.MIN_VALUE;
TimedVcsCommit lastCommit = null;
for (TimedVcsCommit commit : commits) {
- if (commit.getTime() > maxTimeStamp) {
+ if (commit.getTime() >= maxTimeStamp) {
maxTimeStamp = commit.getTime();
lastCommit = commit;
}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspection.java
index 660a88f..a2c9307f 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 Bas Leijdekkers
+ * Copyright 2013-2014 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -91,27 +91,14 @@
return;
}
final PsiExpression secondArgument = arguments[1];
- if (!ExpressionUtils.hasStringType(secondArgument)) {
- return;
- }
- final String value = (String)ExpressionUtils.computeConstantExpression(secondArgument);
- if (value == null) {
- return;
- }
- placeholderCount = countPlaceholders(value);
- argumentCount = hasThrowableType(arguments[arguments.length - 1]) ? arguments.length - 3 : arguments.length - 2;
+ placeholderCount = countPlaceholders(secondArgument);
+ argumentCount = countArguments(arguments, 2);
}
- else if (ExpressionUtils.hasStringType(firstArgument)) {
- final String value = (String)ExpressionUtils.computeConstantExpression(firstArgument);
- if (value == null) {
- return;
- }
- placeholderCount = countPlaceholders(value);
- argumentCount = hasThrowableType(arguments[arguments.length - 1]) ? arguments.length - 2 : arguments.length - 1;
- } else {
- return;
+ else {
+ placeholderCount = countPlaceholders(firstArgument);
+ argumentCount = countArguments(arguments, 1);
}
- if (placeholderCount == argumentCount) {
+ if (placeholderCount < 0 || argumentCount < 0 || placeholderCount == argumentCount) {
return;
}
registerMethodCallError(expression, Integer.valueOf(argumentCount), Integer.valueOf(placeholderCount));
@@ -131,16 +118,44 @@
return InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_LANG_THROWABLE);
}
- public static int countPlaceholders(String value) {
+ public static int countPlaceholders(PsiExpression argument) {
+ final Object value = ExpressionUtils.computeConstantExpression(argument);
+ if (!(value instanceof String)) {
+ return -1;
+ }
+ final String string = (String)value;
int count = 0;
- int index = value.indexOf("{}");
+ int index = string.indexOf("{}");
while (index >= 0) {
- if (index <= 0 || value.charAt(index - 1) != '\\') {
+ if (index == 0 || string.charAt(index - 1) != '\\') {
count++;
}
- index = value.indexOf("{}", index + 1);
+ index = string.indexOf("{}", index + 1);
}
return count;
}
+
+ private static int countArguments(PsiExpression[] arguments, int countFrom) {
+ if (arguments.length <= countFrom) {
+ return 0;
+ }
+ final int count = arguments.length - countFrom;
+ if (count == 1) {
+ final PsiExpression argument = arguments[countFrom];
+ final PsiType argumentType = argument.getType();
+ if (argumentType instanceof PsiArrayType) {
+ if (argumentType.equalsToText("java.lang.Object[]") && argument instanceof PsiNewExpression) {
+ final PsiNewExpression newExpression = (PsiNewExpression)argument;
+ final PsiArrayInitializerExpression arrayInitializerExpression = newExpression.getArrayInitializer();
+ if (arrayInitializerExpression != null) {
+ return arrayInitializerExpression.getInitializers().length;
+ }
+ }
+ return -1;
+ }
+ }
+ final PsiExpression lastArgument = arguments[arguments.length - 1];
+ return hasThrowableType(lastArgument) ? count - 1 : count;
+ }
}
}
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspectionTest.java
index c122583..1bd7fea 100644
--- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspectionTest.java
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/logging/PlaceholderCountMatchesArgumentCountInspectionTest.java
@@ -80,11 +80,31 @@
public void testNoSlf4j() {
doTest("class FalsePositiveSLF4J {\n" +
" public void method( DefinitelyNotSLF4J definitelyNotSLF4J ) {\n" +
- " definitelyNotSLF4J.trace( \"not a trace message\", \"not a trace parameter\" );\n" +
+ " definitelyNotSLF4J.info( \"not a trace message\", \"not a trace parameter\" );\n" +
" }\n" +
" public interface DefinitelyNotSLF4J {\n" +
- " void trace( String firstParameter, Object secondParameter );\n" +
+ " void info( String firstParameter, Object secondParameter );\n" +
" }\n" +
"}");
}
+
+ public void testArrayArgument() {
+ doTest("import org.slf4j.*;" +
+ "class X {" +
+ " Logger LOG = LoggerFactory.getLogger( X.class );" +
+ " void m(String a, int b, Object c) {" +
+ " LOG.info(\"schnizzle {} for blurb {} in quark {}\", new Object[] {a, b, c});" +
+ " }" +
+ "}");
+ }
+
+ public void testUncountableArray() {
+ doTest("import org.slf4j.*;" +
+ "class X {" +
+ " Logger LOG = LoggerFactory.getLogger( X.class );" +
+ " void m(Object[] objects) {" +
+ " LOG.info(\"deep cover {} quantum disstressor {} at light speed {}\", objects);" +
+ " }" +
+ "}");
+ }
}
\ No newline at end of file
diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.java b/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.java
index 9b9d910..66ea6e3 100644
--- a/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.java
+++ b/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.java
@@ -36,6 +36,7 @@
import com.maddyhome.idea.copyright.CopyrightProfile;
import com.maddyhome.idea.copyright.options.LanguageOptions;
import com.maddyhome.idea.copyright.util.FileTypeUtil;
+import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.LinkedHashSet;
@@ -321,25 +322,28 @@
@Override
public void run() {
Document doc = FileDocumentManager.getInstance().getDocument(getRoot());
- PsiDocumentManager.getInstance(file.getProject()).doPostponedOperationsAndUnblockDocument(doc);
- for (CommentAction action : actions) {
- int start = action.getStart();
- int end = action.getEnd();
-
- switch (action.getType()) {
- case CommentAction.ACTION_INSERT:
- String comment = getCommentText(action.getPrefix(), action.getSuffix());
- if (!comment.isEmpty()) {
- doc.insertString(start, comment);
- }
- break;
- case CommentAction.ACTION_REPLACE:
- doc.replaceString(start, end, getCommentText("", ""));
- break;
- case CommentAction.ACTION_DELETE:
- doc.deleteString(start, end);
- break;
+ if (doc != null) {
+ PsiDocumentManager.getInstance(file.getProject()).doPostponedOperationsAndUnblockDocument(doc);
+ for (CommentAction action : actions) {
+ int start = action.getStart();
+ int end = action.getEnd();
+
+ switch (action.getType()) {
+ case CommentAction.ACTION_INSERT:
+ String comment = getCommentText(action.getPrefix(), action.getSuffix());
+ if (!comment.isEmpty()) {
+ doc.insertString(start, comment);
+ }
+ break;
+ case CommentAction.ACTION_REPLACE:
+ doc.replaceString(start, end, getCommentText("", ""));
+ break;
+ case CommentAction.ACTION_DELETE:
+ doc.deleteString(start, end);
+ break;
+ }
}
+ PsiDocumentManager.getInstance(file.getProject()).commitDocument(doc);
}
}
});
@@ -423,7 +427,7 @@
}
@Override
- public int compareTo(CommentAction object) {
+ public int compareTo(@NotNull CommentAction object) {
int s = object.getStart();
int diff = s - start;
if (diff == 0) {
diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/CachedXmlDocumentSet.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/CachedXmlDocumentSet.java
index 548d190..9edbad2 100644
--- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/CachedXmlDocumentSet.java
+++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/CachedXmlDocumentSet.java
@@ -23,7 +23,6 @@
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.HashMap;
-import com.intellij.util.io.fs.IFile;
import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.output.EclipseJDOMUtil;
@@ -44,8 +43,12 @@
this.project = project;
}
- public Document read (final String name) throws IOException, JDOMException {
- return (Document)load(name).clone();
+ public Document read(final String name) throws IOException, JDOMException {
+ return read(name, true);
+ }
+
+ public Document read(final String name, final boolean refresh) throws IOException, JDOMException {
+ return (Document)load(name, refresh).clone();
}
public void write(Document document, String name) throws IOException {
@@ -66,13 +69,18 @@
public boolean exists(String name) {
assertKnownName(name);
- return !deletedContent.contains(name) && getVFile(name) != null;
+ return !deletedContent.contains(name) && getVFile(name, false) != null;
}
@Nullable
protected VirtualFile getVFile(final String name) {
+ return getVFile(name, true);
+ }
+
+ @Nullable
+ protected VirtualFile getVFile(final String name, boolean refresh) {
final VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(new File(getParent(name), name));
- if (file != null) {
+ if (file != null && refresh) {
file.refresh(false, true);
if (!file.isValid()) return null;
}
@@ -107,7 +115,7 @@
}
}
- protected Document load(final String name) throws IOException, JDOMException {
+ protected Document load(final String name, boolean refresh) throws IOException, JDOMException {
assertKnownName(name);
final Document logical = modifiedContent.get(name);
if (logical != null) {
@@ -116,7 +124,7 @@
Document physical = savedContent.get(name);
if (physical == null) {
- final VirtualFile vFile = deletedContent.contains(name) ? null : getVFile(name);
+ final VirtualFile vFile = deletedContent.contains(name) ? null : getVFile(name, refresh);
if (vFile == null) {
throw new IOException(name + ": file does not exist");
}
@@ -136,7 +144,7 @@
public void preload() {
for (String key : nameToDir.keySet()) {
try {
- load(key);
+ load(key, true);
}
catch (IOException ignore) {
}
diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java
index 6787a9c4..5f06150 100644
--- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java
+++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/config/EclipseClasspathStorageProvider.java
@@ -172,7 +172,7 @@
DotProjectFileHelper.saveDotProjectFile(module, fileCache.getParent(EclipseXml.PROJECT_FILE));
fileCache.delete(oldEmlName);
fileCache.register(newName + EclipseXml.IDEA_SETTINGS_POSTFIX, ClasspathStorage.getModuleDir(module));
- fileCache.load(newName + EclipseXml.IDEA_SETTINGS_POSTFIX);
+ fileCache.load(newName + EclipseXml.IDEA_SETTINGS_POSTFIX, true);
}
catch (IOException ignore) {
}
@@ -208,7 +208,7 @@
classpathReader.init(model);
if (documentSet.exists(EclipseXml.CLASSPATH_FILE)) {
classpathReader.readClasspath(model, new ArrayList<String>(), new ArrayList<String>(), usedVariables, new HashSet<String>(), null,
- documentSet.read(EclipseXml.CLASSPATH_FILE).getRootElement());
+ documentSet.read(EclipseXml.CLASSPATH_FILE, false).getRootElement());
}
else {
EclipseClasspathReader.setOutputUrl(model, path + "/bin");
diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/IdeaSpecificSettings.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/IdeaSpecificSettings.java
index 865d7c2..ffd71fd 100644
--- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/IdeaSpecificSettings.java
+++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/conversion/IdeaSpecificSettings.java
@@ -74,7 +74,7 @@
}
public static void readIDEASpecific(ModifiableRootModel model, CachedXmlDocumentSet documentSet, String eml) throws InvalidDataException, IOException, JDOMException {
- new IdeaSpecificSettings().readIDEASpecific(documentSet.read(eml).getRootElement(), model, null, new HashMap<String, String>());
+ new IdeaSpecificSettings().readIDEASpecific(documentSet.read(eml, false).getRootElement(), model, null, new HashMap<String, String>());
}
@Override
diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml
index 0c98e14..62640bf 100644
--- a/plugins/git4idea/src/META-INF/plugin.xml
+++ b/plugins/git4idea/src/META-INF/plugin.xml
@@ -116,8 +116,6 @@
<logProvider implementation="git4idea.log.GitLogProvider"/>
<vcsChangesViewRefresher implementation="git4idea.changes.GitChangesViewRefresher" />
- <vcs.rootFinder implementation="git4idea.roots.GitRootFinder"/>
-
<projectService
serviceInterface="git4idea.history.wholeTree.LogFactoryService"
serviceImplementation="git4idea.history.wholeTree.LogFactoryService"/>
diff --git a/plugins/git4idea/src/git4idea/GitVcs.java b/plugins/git4idea/src/git4idea/GitVcs.java
index 6d62a07..714f609 100644
--- a/plugins/git4idea/src/git4idea/GitVcs.java
+++ b/plugins/git4idea/src/git4idea/GitVcs.java
@@ -46,7 +46,6 @@
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vcs.merge.MergeProvider;
import com.intellij.openapi.vcs.rollback.RollbackEnvironment;
-import com.intellij.openapi.vcs.roots.VcsRootDetectInfo;
import com.intellij.openapi.vcs.roots.VcsRootDetector;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.openapi.vcs.update.UpdateEnvironment;
@@ -89,6 +88,7 @@
import javax.swing.event.HyperlinkEvent;
import java.io.File;
import java.text.SimpleDateFormat;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -586,8 +586,8 @@
public void enableIntegration() {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
- VcsRootDetectInfo detectInfo = new VcsRootDetector(myProject).detect();
- new GitIntegrationEnabler(myProject, myGit, myPlatformFacade).enable(detectInfo);
+ Collection<VcsRoot> roots = ServiceManager.getService(myProject, VcsRootDetector.class).detect();
+ new GitIntegrationEnabler(myProject, myGit, myPlatformFacade).enable(roots);
}
});
}
diff --git a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java
index ee75d19..7331fd7 100644
--- a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java
+++ b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java
@@ -113,22 +113,16 @@
for (VirtualFile root : GitUtil.gitRoots(Arrays.asList(filesToCheckin))) {
VirtualFile mergeMsg = root.findFileByRelativePath(GitRepositoryFiles.GIT_MERGE_MSG);
VirtualFile squashMsg = root.findFileByRelativePath(GitRepositoryFiles.GIT_SQUASH_MSG);
- VirtualFile normalMsg = root.findFileByRelativePath(GitRepositoryFiles.GIT_COMMIT_EDITMSG);
try {
- if (mergeMsg == null && squashMsg == null && normalMsg == null) {
+ if (mergeMsg == null && squashMsg == null) {
continue;
}
-
String encoding = GitConfigUtil.getCommitEncoding(myProject, root);
-
if (mergeMsg != null) {
messages.add(loadMessage(mergeMsg, encoding));
}
- else if (squashMsg != null) {
- messages.add(loadMessage(squashMsg, encoding));
- }
else {
- messages.add(loadMessage(normalMsg, encoding));
+ messages.add(loadMessage(squashMsg, encoding));
}
}
catch (IOException e) {
diff --git a/plugins/git4idea/src/git4idea/config/GitVersion.java b/plugins/git4idea/src/git4idea/config/GitVersion.java
index 794ca8b..57ac40d 100644
--- a/plugins/git4idea/src/git4idea/config/GitVersion.java
+++ b/plugins/git4idea/src/git4idea/config/GitVersion.java
@@ -69,7 +69,7 @@
public static final GitVersion NULL = new GitVersion(0, 0, 0, 0, Type.NULL);
private static final Pattern FORMAT = Pattern.compile(
- "git version (\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?(.*)", Pattern.CASE_INSENSITIVE);
+ "git version (\\d+)\\.(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(.*)", Pattern.CASE_INSENSITIVE);
private static final Logger LOG = Logger.getInstance(GitVersion.class.getName());
diff --git a/plugins/git4idea/src/git4idea/roots/GitIntegrationEnabler.java b/plugins/git4idea/src/git4idea/roots/GitIntegrationEnabler.java
index a9e0c6e..4e9533a 100644
--- a/plugins/git4idea/src/git4idea/roots/GitIntegrationEnabler.java
+++ b/plugins/git4idea/src/git4idea/roots/GitIntegrationEnabler.java
@@ -22,8 +22,8 @@
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsDirectoryMapping;
import com.intellij.openapi.vcs.VcsRoot;
-import com.intellij.openapi.vcs.roots.VcsRootDetectInfo;
import com.intellij.openapi.vcs.roots.VcsRootErrorsFinder;
+import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
@@ -56,9 +56,9 @@
myPlatformFacade = platformFacade;
}
- public void enable(@NotNull VcsRootDetectInfo detectInfo) {
+ public void enable(@NotNull Collection<VcsRoot> vcsRoots) {
Notificator notificator = myPlatformFacade.getNotificator(myProject);
- Collection<VcsRoot> gitRoots = ContainerUtil.filter(detectInfo.getRoots(), new Condition<VcsRoot>() {
+ Collection<VcsRoot> gitRoots = ContainerUtil.filter(vcsRoots, new Condition<VcsRoot>() {
@Override
public boolean value(VcsRoot root) {
AbstractVcs gitVcs = root.getVcs();
@@ -77,13 +77,24 @@
}
else {
assert !roots.isEmpty();
- if (roots.size() > 1 || detectInfo.projectIsBelowVcs()) {
+ if (roots.size() > 1 || isProjectBelowVcs(roots)) {
notifyAddedRoots(notificator, roots);
}
addVcsRoots(roots);
}
}
+ private boolean isProjectBelowVcs(@NotNull Collection<VirtualFile> gitRoots) {
+ //check if there are vcs roots strictly above the project dir
+ VirtualFile baseDir = myProject.getBaseDir();
+ for (VirtualFile root : gitRoots) {
+ if (VfsUtilCore.isAncestor(root, baseDir, true)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private static void notifyAddedRoots(Notificator notificator, Collection<VirtualFile> roots) {
notificator.notifySuccess("", String.format("Added Git %s: %s", pluralize("root", roots.size()), joinRootsPaths(roots)));
}
diff --git a/plugins/git4idea/src/git4idea/roots/GitRootFinder.java b/plugins/git4idea/src/git4idea/roots/GitRootFinder.java
deleted file mode 100644
index 01e2099..0000000
--- a/plugins/git4idea/src/git4idea/roots/GitRootFinder.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package git4idea.roots;
-
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vcs.VcsDirectoryMapping;
-import com.intellij.openapi.vcs.VcsRoot;
-import com.intellij.openapi.vcs.VcsRootFinder;
-import com.intellij.openapi.vcs.roots.VcsRootDetectInfo;
-import com.intellij.openapi.vcs.roots.VcsRootDetector;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.containers.ContainerUtilRt;
-import git4idea.GitVcs;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * @author Denis Zhdanov
- * @since 7/18/13 6:02 PM
- */
-public class GitRootFinder implements VcsRootFinder {
-
- @NotNull private final Project myProject;
-
- public GitRootFinder(@NotNull Project project) {
- myProject = project;
- }
-
- @NotNull
- @Override
- public Collection<VcsDirectoryMapping> findRoots(@NotNull VirtualFile root) {
- VcsRootDetectInfo info = new VcsRootDetector(myProject).detect(root);
- Collection<VcsRoot> roots = info.getRoots();
- if (roots.isEmpty()) {
- return Collections.emptyList();
- }
- Collection<VcsDirectoryMapping> result = ContainerUtilRt.newArrayList();
- for (VcsRoot vcsRoot : roots) {
- VirtualFile vFile = vcsRoot.getPath();
- if (vFile != null) {
- result.add(new VcsDirectoryMapping(vFile.getPath(), GitVcs.getKey().getName()));
- }
- }
- return result;
- }
-}
diff --git a/plugins/git4idea/tests/git4idea/roots/GitIntegrationEnablerTest.java b/plugins/git4idea/tests/git4idea/roots/GitIntegrationEnablerTest.java
index 8643348..37b1d92 100644
--- a/plugins/git4idea/tests/git4idea/roots/GitIntegrationEnablerTest.java
+++ b/plugins/git4idea/tests/git4idea/roots/GitIntegrationEnablerTest.java
@@ -22,7 +22,6 @@
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.VcsRoot;
import com.intellij.openapi.vcs.VcsTestUtil;
-import com.intellij.openapi.vcs.roots.VcsRootDetectInfo;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
@@ -38,7 +37,7 @@
import java.io.File;
import java.util.*;
-import static junit.framework.Assert.*;
+import static org.junit.Assert.*;
/**
* @author Nadya Zabrodina
@@ -63,7 +62,7 @@
public void oneRootForTheWholeProjectThenJustAddVcsrRoot() {
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("git_init", Collections.<String>emptyList());
- doTest(given(Arrays.asList("."), false),
+ doTest(given(Arrays.asList(".")),
map, null);
}
@@ -74,7 +73,7 @@
map.put("vcs_roots", VcsTestUtil.toAbsolute(Arrays.asList("."), myProject));
- doTest(given(Collections.<String>emptyList(), false),
+ doTest(given(Collections.<String>emptyList()),
map, notification("Created Git repository in " + myProjectRoot));
}
@@ -83,7 +82,7 @@
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("git_init", Collections.<String>emptyList());
- doTest(given(Arrays.asList(".."), true),
+ doTest(given(Arrays.asList("..")),
map, notification("Added Git root: " + myTestRoot));
}
@@ -92,7 +91,7 @@
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("git_init", Collections.<String>emptyList());
- doTest(given(Arrays.asList(".", "community"), false),
+ doTest(given(Arrays.asList(".", "community")),
map, notification("Added Git roots: " + myProjectRoot + ", " + getPresentationForRoot("community")));
}
@@ -101,7 +100,7 @@
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("git_init", Collections.<String>emptyList());
- doTest(given(Arrays.asList("..", "community"), true),
+ doTest(given(Arrays.asList("..", "community")),
map, notification("Added Git roots: " + myTestRoot + ", " + getPresentationForRoot("community")));
}
@@ -110,16 +109,16 @@
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("git_init", Collections.<String>emptyList());
- doTest(given(Arrays.asList("community", "contrib"), false),
+ doTest(given(Arrays.asList("community", "contrib")),
map, notification(
"Added Git roots: " + getPresentationForRoot("community") + ", " + getPresentationForRoot("contrib")));
}
- private void doTest(@NotNull VcsRootDetectInfo detectInfo, @NotNull Map<String, List<String>> map, @Nullable Notification notification) {
+ private void doTest(@NotNull Collection<VcsRoot> vcsRoots, @NotNull Map<String, List<String>> map, @Nullable Notification notification) {
//default
if (map.get("vcs_roots") == null) {
- map.put("vcs_roots", ContainerUtil.map(detectInfo.getRoots(), new Function<VcsRoot, String>() {
+ map.put("vcs_roots", ContainerUtil.map(vcsRoots, new Function<VcsRoot, String>() {
@Override
public String fun(VcsRoot root) {
@@ -129,7 +128,7 @@
}));
}
- new GitIntegrationEnabler(myProject, myGit, myPlatformFacade).enable(detectInfo);
+ new GitIntegrationEnabler(myProject, myGit, myPlatformFacade).enable(vcsRoots);
assertVcsRoots(map.get("vcs_roots"));
assertGitInit(map.get("git_init"));
@@ -148,14 +147,14 @@
VcsTestUtil.assertEqualCollections(expectedVcsRoots, getPaths(actualRoots));
}
- VcsRootDetectInfo given(@NotNull Collection<String> roots, boolean below) {
- return new VcsRootDetectInfo(ContainerUtil.map(roots, new Function<String, VcsRoot>() {
+ Collection<VcsRoot> given(@NotNull Collection<String> roots) {
+ return ContainerUtil.map(roots, new Function<String, VcsRoot>() {
@Override
public VcsRoot fun(String s) {
return new VcsRoot(myVcs, new MockVirtualFile(VcsTestUtil.toAbsolute(s, myProject)));
}
- }), below);
+ });
}
Notification notification(String content) {
diff --git a/plugins/git4idea/tests/git4idea/tests/GitVersionTest.java b/plugins/git4idea/tests/git4idea/tests/GitVersionTest.java
index 798d508..52232a1 100644
--- a/plugins/git4idea/tests/git4idea/tests/GitVersionTest.java
+++ b/plugins/git4idea/tests/git4idea/tests/GitVersionTest.java
@@ -17,7 +17,7 @@
import com.intellij.openapi.util.SystemInfo;
import git4idea.config.GitVersion;
-import org.testng.annotations.Test;
+import org.junit.Test;
import java.lang.reflect.Field;
@@ -34,7 +34,8 @@
new TestGitVersion("git version 1.7.3.3", 1, 7, 3, 3),
new TestGitVersion("git version 1.7.3.5.gb27be", 1, 7, 3, 5),
new TestGitVersion("git version 1.7.4-rc1", 1, 7, 4, 0),
- new TestGitVersion("git version 1.7.7.5 (Apple Git-24)", 1, 7, 7, 5)
+ new TestGitVersion("git version 1.7.7.5 (Apple Git-24)", 1, 7, 7, 5),
+ new TestGitVersion("git version 1.9.rc0.143.g6fd479e", 1, 9, 0, 0)
};
private static final TestGitVersion[] msysTests = {
diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java
index b30f57b..4d70975 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java
@@ -23,7 +23,9 @@
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.ui.Splitter;
+import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.ChangeListManager;
@@ -284,7 +286,8 @@
// ask for files to add
final List<VirtualFile> trackedFiles = ChangeListManager.getInstance(project).getAffectedFiles();
- final Collection<VirtualFile> untrackedFiles = repository.getUntrackedFilesHolder().retrieveUntrackedFiles();
+ final Collection<VirtualFile> untrackedFiles = filterOutIgnored(project,
+ repository.getUntrackedFilesHolder().retrieveUntrackedFiles());
final List<VirtualFile> allFiles = new ArrayList<VirtualFile>();
allFiles.addAll(trackedFiles);
allFiles.addAll(untrackedFiles);
@@ -337,6 +340,18 @@
return true;
}
+ @NotNull
+ private static Collection<VirtualFile> filterOutIgnored(@NotNull Project project, @NotNull Collection<VirtualFile> files) {
+ final ChangeListManager changeListManager = ChangeListManager.getInstance(project);
+ final FileIndexFacade fileIndex = FileIndexFacade.getInstance(project);
+ return ContainerUtil.filter(files, new Condition<VirtualFile>() {
+ @Override
+ public boolean value(VirtualFile file) {
+ return !changeListManager.isIgnoredFile(file) && !fileIndex.isExcludedFile(file);
+ }
+ });
+ }
+
private static boolean pushCurrentBranch(@NotNull Project project,
@NotNull GitRepository repository,
@NotNull String remoteName,
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImpl.java
index 875d9cc..5572290 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImpl.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImpl.java
@@ -22,14 +22,13 @@
import org.gradle.plugins.ide.internal.IdeDependenciesExtractor;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.model.BuildScriptClasspathModel;
+import org.jetbrains.plugins.gradle.model.ClasspathEntryModel;
import org.jetbrains.plugins.gradle.model.ModelBuilderService;
import org.jetbrains.plugins.gradle.model.internal.BuildScriptClasspathModelImpl;
import org.jetbrains.plugins.gradle.model.internal.ClasspathEntryModelImpl;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
/**
* @author Vladislav.Soroka
@@ -37,6 +36,8 @@
*/
public class ModelBuildScriptClasspathBuilderImpl implements ModelBuilderService {
+ private final Map<String, BuildScriptClasspathModelImpl> cache = new ConcurrentHashMap<String, BuildScriptClasspathModelImpl>();
+
@Override
public boolean canBuild(String modelName) {
return BuildScriptClasspathModel.class.getName().equals(modelName);
@@ -45,6 +46,9 @@
@Nullable
@Override
public Object buildAll(final String modelName, final Project project) {
+ BuildScriptClasspathModelImpl buildScriptClasspath = cache.get(project.getPath());
+ if (buildScriptClasspath != null) return buildScriptClasspath;
+
boolean offline = false;
boolean downloadJavadoc = false;
boolean downloadSources = true;
@@ -60,13 +64,22 @@
}
}
+ buildScriptClasspath = new BuildScriptClasspathModelImpl();
+ Project parent = project.getParent();
+ if (parent != null) {
+ BuildScriptClasspathModelImpl parentBuildScriptClasspath = (BuildScriptClasspathModelImpl)buildAll(modelName, parent);
+ if (parentBuildScriptClasspath != null) {
+ for (ClasspathEntryModel classpathEntryModel : parentBuildScriptClasspath.getClasspath()) {
+ buildScriptClasspath.add(classpathEntryModel);
+ }
+ }
+ }
+
final IdeDependenciesExtractor dependenciesExtractor = new IdeDependenciesExtractor();
final Configuration configuration = project.getBuildscript().getConfigurations().findByName("classpath");
Collection<Configuration> plusConfigurations = Collections.singletonList(configuration);
- BuildScriptClasspathModelImpl buildScriptClasspath = new BuildScriptClasspathModelImpl();
-
if (!offline) {
// download sources and/or javadoc
List<IdeDependenciesExtractor.IdeRepoFileDependency> repoFileDependencies = dependenciesExtractor.extractRepoFileDependencies(
@@ -88,6 +101,7 @@
buildScriptClasspath.add(new ClasspathEntryModelImpl(dependency.getFile(), null, null));
}
+ cache.put(project.getPath(), buildScriptClasspath);
return buildScriptClasspath;
}
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java
index 00d9ca5..67cb359 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/task/GradleTaskManager.java
@@ -125,8 +125,11 @@
public boolean cancelTask(@NotNull ExternalSystemTaskId id, @NotNull ExternalSystemTaskNotificationListener listener)
throws ExternalSystemException {
- for (GradleTaskManagerExtension gradleTaskManagerExtension : GradleTaskManagerExtension.EP_NAME.getExtensions()) {
- if (gradleTaskManagerExtension.cancelTask(id, listener)) return true;
+ // extension points are available only in IDE process
+ if (ExternalSystemApiUtil.isInProcessMode(GradleConstants.SYSTEM_ID)) {
+ for (GradleTaskManagerExtension gradleTaskManagerExtension : GradleTaskManagerExtension.EP_NAME.getExtensions()) {
+ if (gradleTaskManagerExtension.cancelTask(id, listener)) return true;
+ }
}
// TODO replace with cancellation gradle API invocation when it will be ready, see http://issues.gradle.org/browse/GRADLE-1539
diff --git a/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/build.gradle b/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/build.gradle
index 5b09fca..45214e3 100644
--- a/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/build.gradle
+++ b/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/build.gradle
@@ -7,3 +7,11 @@
}
}
}
+
+project("baseModule") {
+ buildscript {
+ dependencies {
+ classpath files("lib/inheritedDep.jar")
+ }
+ }
+}
diff --git a/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/settings.gradle b/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/settings.gradle
index 0297887..20bd8ca 100644
--- a/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/settings.gradle
+++ b/plugins/gradle/testData/testModelBuildScriptClasspathBuilder/settings.gradle
@@ -2,3 +2,5 @@
include 'moduleWithoutAdditionalClasspath'
include 'moduleWithAdditionalClasspath'
+include 'baseModule'
+include 'baseModule:moduleWithInheritedClasspath'
\ No newline at end of file
diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImplTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImplTest.java
index d812d8d..d802d08 100644
--- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImplTest.java
+++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/model/builder/ModelBuildScriptClasspathBuilderImplTest.java
@@ -55,20 +55,28 @@
ClasspathEntryModel classpathEntry = classpathModel.getClasspath().getAt(0);
assertEquals("someDep.jar", classpathEntry.getClassesFile().getName());
}
+ else if (module.getName().equals("baseModule") ||
+ module.getName().equals("moduleWithInheritedClasspath")) {
+ assertNotNull("Null build classpath for module: " + module.getName(), classpathModel);
+ assertEquals("Wrong build classpath for module: " + module.getName(), 1, classpathModel.getClasspath().size());
+
+ ClasspathEntryModel classpathEntry = classpathModel.getClasspath().getAt(0);
+ assertEquals("Wrong build classpath for module: " + module.getName(), "inheritedDep.jar", classpathEntry.getClassesFile().getName());
+ }
else if (module.getName().equals("moduleWithoutAdditionalClasspath") ||
module.getName().equals("testModelBuildScriptClasspathBuilder")) {
- assertNotNull(classpathModel);
- assertTrue(classpathModel.getClasspath().isEmpty());
+ assertNotNull("Wrong build classpath for module: " + module.getName(), classpathModel);
+ assertTrue("Wrong build classpath for module: " + module.getName(), classpathModel.getClasspath().isEmpty());
}
else {
- fail();
+ fail("Unexpected module found: " + module.getName());
}
return classpathModel;
}
});
- assertEquals(3, ideaModule.size());
+ assertEquals(5, ideaModule.size());
}
@Override
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java
index 58ee7a9..198db847 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
import com.intellij.psi.codeStyle.SuggestedNameInfo;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.filters.FilterPositionUtil;
+import com.intellij.psi.impl.light.LightElement;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.InheritanceUtil;
@@ -65,7 +66,6 @@
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.CompleteReferenceExpression;
-import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrBindingVariable;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.refactoring.DefaultGroovyVariableNameValidator;
@@ -451,7 +451,7 @@
object = ((GroovyResolveResult)object).getElement();
}
- if (object instanceof GrBindingVariable && ((GrBindingVariable)object).getName().contains(CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED)) {
+ if (isLightElementDeclaredDuringCompletion(object)) {
return;
}
@@ -495,6 +495,16 @@
return EmptyRunnable.INSTANCE;
}
+ private static boolean isLightElementDeclaredDuringCompletion(Object object) {
+ if (!(object instanceof LightElement && object instanceof PsiNamedElement)) return false;
+ final String name = ((PsiNamedElement)object).getName();
+ if (name == null) return false;
+
+ return name.contains(CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED.trim()) ||
+ name.contains(DUMMY_IDENTIFIER_DECAPITALIZED.trim());
+ }
+
+
private static Runnable addStaticMembers(CompletionParameters parameters,
final PrefixMatcher matcher,
final Map<PsiModifierListOwner, LookupElement> staticMembers, final Consumer<LookupElement> consumer) {
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java
index f3779a1..152ceb5 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java
@@ -522,7 +522,8 @@
@Override
public void visitCaseLabel(GrCaseLabel caseLabel) {
final PsiElement parent = caseLabel.getParent().getParent();
- assert parent instanceof GrSwitchStatement : parent + " of class " + parent.getClass();
+ if (!(parent instanceof GrSwitchStatement)) return;
+
final GrExpression condition = ((GrSwitchStatement)parent).getCondition();
if (condition == null) return;
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopup.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopup.java
index 5cdbd36..f272547 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopup.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopup.java
@@ -29,7 +29,6 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.repo.HgRepository;
-import org.zmlx.hg4idea.repo.HgRepositoryImpl;
import org.zmlx.hg4idea.util.HgUtil;
import javax.swing.*;
@@ -110,10 +109,12 @@
popupGroup.addSeparator("Repositories");
boolean isMultiRepoConfig = repositories.size() > 1;
for (VirtualFile repository : repositories) {
- HgRepository repo = HgRepositoryImpl.getInstance(repository, myProject, myProject);
- popupGroup.add(new RootAction<HgRepository>(repo, isMultiRepoConfig ? myCurrentRepository : null,
- new HgBranchPopupActions(repo.getProject(), repo).createActions(null),
- HgUtil.getDisplayableBranchText(repo)));
+ HgRepository repo = HgUtil.getRepositoryManager(myProject).getRepositoryForRoot(repository);
+ if (repo != null) {
+ popupGroup.add(new RootAction<HgRepository>(repo, isMultiRepoConfig ? myCurrentRepository : null,
+ new HgBranchPopupActions(repo.getProject(), repo).createActions(null),
+ HgUtil.getDisplayableBranchText(repo)));
+ }
}
return popupGroup;
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java
index 648309f..61cf991 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java
@@ -20,7 +20,6 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.repo.HgRepository;
-import org.zmlx.hg4idea.repo.HgRepositoryImpl;
import org.zmlx.hg4idea.util.HgUtil;
import java.util.Collection;
@@ -33,19 +32,18 @@
@Override
protected void execute(@NotNull Project project, @NotNull Collection<VirtualFile> repositories, @Nullable VirtualFile selectedRepo) {
- HgRepository repository;
+ HgRepository repository = null;
if (selectedRepo != null) {
- repository = HgRepositoryImpl.getInstance(selectedRepo, project, project);
+ repository = HgUtil.getRepositoryManager(project).getRepositoryForRoot(selectedRepo);
}
else {
VirtualFile selectedRoot = HgUtil.getRootForSelectedFile(project);
if (selectedRoot != null) {
- repository = HgRepositoryImpl.getInstance(selectedRoot, project, project);
- }
- else {
- return;
+ repository = HgUtil.getRepositoryManager(project).getRepositoryForRoot(selectedRoot);
}
}
- HgBranchPopup.getInstance(project, repository).asListPopup().showInFocusCenter();
+ if (repository != null) {
+ HgBranchPopup.getInstance(project, repository).asListPopup().showInFocusCenter();
+ }
}
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java
index 9fc2b16..c538825 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java
@@ -165,7 +165,6 @@
List<String> filterParameters = ContainerUtil.newArrayList();
// branch filter and user filter may be used several times without delimiter
- // or -r options with appropriate revset arguments delimited by '|' or 'and'.
if (!branchFilters.isEmpty()) {
for (VcsLogBranchFilter branchFilter : branchFilters) {
filterParameters.add(prepareParameter("branch", branchFilter.getBranchName()));
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotationProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotationProvider.java
index 5592151..74e5177 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotationProvider.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/annotate/HgAnnotationProvider.java
@@ -16,6 +16,7 @@
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.annotate.AnnotationProvider;
import com.intellij.openapi.vcs.annotate.FileAnnotation;
+import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vfs.VfsUtilCore;
@@ -53,8 +54,10 @@
throw new VcsException("vcs root is null for " + file);
}
final HgFile hgFile = new HgFile(vcsRoot, VfsUtilCore.virtualToIoFile(file));
- HgFile fileToAnnotate = revision instanceof HgFileRevision ? HgUtil
- .getFileNameInTargetRevision(myProject, ((HgFileRevision)revision).getRevisionNumber(), hgFile) : hgFile;
+ HgFile fileToAnnotate = revision instanceof HgFileRevision
+ ? HgUtil.getFileNameInTargetRevision(myProject, ((HgFileRevision)revision).getRevisionNumber(), hgFile)
+ : new HgFile(vcsRoot,
+ HgUtil.getOriginalFileName(hgFile.toFilePath(), ChangeListManager.getInstance(myProject)));
final List<HgAnnotationLine> annotationResult = (new HgAnnotateCommand(myProject)).execute(fileToAnnotate, revision);
final List<HgFileRevision> logResult;
try {
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java
index 6cf3bcad..b0b4c7a 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgRegularUpdater.java
@@ -268,7 +268,7 @@
if (parentAfterUpdate.equals(parentBeforeUpdate)) { // nothing to update => returning not to capture local uncommitted changes
return;
}
- HgStatusCommand statusCommand = new HgStatusCommand.Builder(true).baseRevision(parentBeforeUpdate).targetRevision(
+ HgStatusCommand statusCommand = new HgStatusCommand.Builder(true).ignored(false).unknown(false).baseRevision(parentBeforeUpdate).targetRevision(
parentAfterUpdate).build(project);
Set<HgChange> changes = statusCommand.execute(repo);
for (HgChange change : changes) {
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java
index b1a52f3..61dd6a7 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java
@@ -351,9 +351,10 @@
@NotNull
public static HgFile getFileNameInTargetRevision(Project project, HgRevisionNumber vcsRevisionNumber, HgFile localHgFile) {
- HgStatusCommand statCommand = new HgStatusCommand.Builder(true).unknown(false).baseRevision(vcsRevisionNumber).build(project);
+ //get file name in target revision if it was moved/renamed
+ HgStatusCommand statCommand = new HgStatusCommand.Builder(false).copySource(true).baseRevision(vcsRevisionNumber).build(project);
- Set<HgChange> changes = statCommand.execute(localHgFile.getRepo());
+ Set<HgChange> changes = statCommand.execute(localHgFile.getRepo(), Collections.singletonList(localHgFile.toFilePath()));
for (HgChange change : changes) {
if (change.afterFile().equals(localHgFile)) {
@@ -470,13 +471,15 @@
if (rev1 != null) {
revNumber1 = rev1.getRevisionNumber();
//rev2==null means "compare with local version"
- statusCommand = new HgStatusCommand.Builder(true).copySource(false).baseRevision(revNumber1)
+ statusCommand = new HgStatusCommand.Builder(true).ignored(false).unknown(false).copySource(false).baseRevision(revNumber1)
.targetRevision(rev2 != null ? rev2.getRevisionNumber() : null).build(project);
}
else {
LOG.assertTrue(rev2 != null, "revision1 and revision2 can't both be null. Path: " + path); //rev1 and rev2 can't be null both//
//get initial changes//
- statusCommand = new HgStatusCommand.Builder(true).copySource(false).baseRevision(rev2.getRevisionNumber()).build(project);
+ statusCommand =
+ new HgStatusCommand.Builder(true).ignored(false).unknown(false).copySource(false).baseRevision(rev2.getRevisionNumber())
+ .build(project);
}
Collection<HgChange> hgChanges = statusCommand.execute(root, Collections.singleton(path));
@@ -484,11 +487,11 @@
//convert output changes to standart Change class
for (HgChange hgChange : hgChanges) {
FileStatus status = convertHgDiffStatus(hgChange.getStatus());
- if (status != FileStatus.UNKNOWN && status!= FileStatus.IGNORED) {
+ if (status != FileStatus.UNKNOWN) {
changes.add(createChange(project, root, hgChange.beforeFile().getRelativePath(), revNumber1,
hgChange.afterFile().getRelativePath(),
rev2 != null ? rev2.getRevisionNumber() : null, status));
- }
+ }
}
return changes;
}
diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java
index ef5d245..ec99bd5 100644
--- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java
+++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java
@@ -23,6 +23,7 @@
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.text.StringUtil;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.model.MavenArchetype;
import org.jetbrains.idea.maven.model.MavenId;
@@ -197,6 +198,12 @@
return true;
}
+ private static void setTestIfEmpty(@NotNull JTextField artifactIdField, @Nullable String text) {
+ if (StringUtil.isEmpty(artifactIdField.getText())) {
+ artifactIdField.setText(StringUtil.notNullize(text));
+ }
+ }
+
@Override
public void updateStep() {
if (myArchetypes != null && myArchetypes.isSkipUpdateUI()) return;
@@ -210,14 +217,14 @@
MavenId projectId = myBuilder.getProjectId();
if (projectId == null) {
- myArtifactIdField.setText(myBuilder.getName());
- myGroupIdField.setText(myParent == null ? myBuilder.getName() : myParent.getMavenId().getGroupId());
- myVersionField.setText(myParent == null ? "1.0-SNAPSHOT" : myParent.getMavenId().getVersion());
+ setTestIfEmpty(myArtifactIdField, myBuilder.getName());
+ setTestIfEmpty(myGroupIdField, myParent == null ? myBuilder.getName() : myParent.getMavenId().getGroupId());
+ setTestIfEmpty(myVersionField, myParent == null ? "1.0-SNAPSHOT" : myParent.getMavenId().getVersion());
}
else {
- myArtifactIdField.setText(projectId.getArtifactId());
- myGroupIdField.setText(projectId.getGroupId());
- myVersionField.setText(projectId.getVersion());
+ setTestIfEmpty(myArtifactIdField, projectId.getArtifactId());
+ setTestIfEmpty(myGroupIdField, projectId.getGroupId());
+ setTestIfEmpty(myVersionField, projectId.getVersion());
}
myInheritGroupIdCheckBox.setSelected(myBuilder.isInheritGroupId());
diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java
index 9256b35..8d2e756 100644
--- a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java
+++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java
@@ -130,7 +130,7 @@
* @see com.intellij.tasks.TaskRepositoryType#getPossibleTaskStates()
*/
public void setTaskState(Task task, TaskState state) throws Exception {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("Setting task to state " + state + " is not supported");
}
// for serialization
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java
index 3eeea41..564c806 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java
@@ -134,7 +134,7 @@
repository.setTaskState(myTask, TaskState.IN_PROGRESS);
}
catch (Exception ex) {
- Messages.showErrorDialog(myProject, "Could not set state for " + myTask.getId(), "Error");
+ Messages.showErrorDialog(myProject, ex.getMessage(), "Cannot Set State For Issue");
LOG.warn(ex);
}
}
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/pivotal/PivotalTrackerRepository.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/pivotal/PivotalTrackerRepository.java
index c0d46b8..12ba067 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/pivotal/PivotalTrackerRepository.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/pivotal/PivotalTrackerRepository.java
@@ -35,6 +35,8 @@
/**
* @author Dennis.Ushakov
+ *
+ * TODO: update to REST APIv5
*/
@Tag("PivotalTracker")
public class PivotalTrackerRepository extends BaseRepositoryImpl {
@@ -333,22 +335,42 @@
@Override
public void setTaskState(Task task, TaskState state) throws Exception {
- if (state != TaskState.IN_PROGRESS) super.setTaskState(task, state);
final String realId = getRealId(task.getId());
if (realId == null) return;
+ final String stateName;
+ switch (state) {
+ case IN_PROGRESS:
+ stateName = "started";
+ break;
+ case RESOLVED:
+ stateName = "finished";
+ break;
+ // may add some others in future
+ default:
+ return;
+ }
String url = API_URL + "/projects/" + myProjectId + "/stories/" + realId;
- url +="?" + encodeUrl("story[current_state]") + "=" + encodeUrl("started");
+ url += "?" + encodeUrl("story[current_state]") + "=" + encodeUrl(stateName);
LOG.info("Updating issue state by id: " + url);
final HttpMethod method = doREST(url, HTTPMethod.PUT);
final InputStream stream = method.getResponseBodyAsStream();
final Element element = new SAXBuilder(false).build(stream).getRootElement();
- final Task story = element.getName().equals("story") ? createIssue(element) : null;
- if (story == null) {
- throw new Exception("Error setting state for: " + url + ", HTTP status code: " + method.getStatusCode() +
- "\n" + element.getText());
+ if (!element.getName().equals("story")) {
+ if (element.getName().equals("errors")) {
+ throw new Exception(extractErrorMessage(element));
+ } else {
+ // unknown error, probably our fault
+ LOG.warn("Error setting state for: " + url + ", HTTP status code: " + method.getStatusCode());
+ throw new Exception(String.format("Cannot set state '%s' for issue.", stateName));
+ }
}
}
+ @NotNull
+ private static String extractErrorMessage(@NotNull Element element) {
+ return StringUtil.notNullize(element.getChild("error").getText());
+ }
+
@Override
public boolean equals(final Object o) {
if (!super.equals(o)) return false;
diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/AbstractTerminalRunner.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/AbstractTerminalRunner.java
index 121958b..6624ad9 100644
--- a/plugins/terminal/src/org/jetbrains/plugins/terminal/AbstractTerminalRunner.java
+++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/AbstractTerminalRunner.java
@@ -165,6 +165,7 @@
});
}
+ @NotNull
protected Project getProject() {
return myProject;
}
diff --git a/python/IntelliLang-python/IntelliLang-python.iml b/python/IntelliLang-python/IntelliLang-python.iml
index b28d5b4..a877c73 100644
--- a/python/IntelliLang-python/IntelliLang-python.iml
+++ b/python/IntelliLang-python/IntelliLang-python.iml
@@ -10,6 +10,7 @@
<orderEntry type="module" module-name="core-api" />
<orderEntry type="module" module-name="IntelliLang" />
<orderEntry type="module" module-name="python-community" />
+ <orderEntry type="module" module-name="lang-impl" />
</component>
</module>
diff --git a/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml b/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml
index ce37b6b..44bab2c 100644
--- a/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml
+++ b/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml
@@ -7,7 +7,6 @@
</extensions>
<extensions defaultExtensionNs="com.intellij">
<patterns.patternClass className="com.jetbrains.python.patterns.PythonPatterns" alias="py"/>
- <multiHostInjector implementation="com.jetbrains.python.intelliLang.PyCommentInjector"/>
<multiHostInjector implementation="com.jetbrains.python.intelliLang.PyConfigurationInjector"/>
<multiHostInjector implementation="com.jetbrains.python.intelliLang.PyTemporaryInjector"/>
</extensions>
diff --git a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyConfigurationInjector.java b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyConfigurationInjector.java
index f672f5d..59974a4 100644
--- a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyConfigurationInjector.java
+++ b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyConfigurationInjector.java
@@ -1,7 +1,10 @@
package com.jetbrains.python.intelliLang;
import com.intellij.lang.Language;
+import com.intellij.lang.injection.MultiHostRegistrar;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
+import com.jetbrains.python.codeInsight.PyInjectionUtil;
import com.jetbrains.python.codeInsight.PyInjectorBase;
import org.intellij.plugins.intelliLang.Configuration;
import org.intellij.plugins.intelliLang.inject.InjectedLanguage;
@@ -15,6 +18,14 @@
* @author vlan
*/
public class PyConfigurationInjector extends PyInjectorBase {
+ @Override
+ public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
+ final PyInjectionUtil.InjectionResult result = registerInjection(registrar, context);
+ if (!result.isStrict()) {
+ InjectorUtils.putInjectedFileUserData(registrar, InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
+ }
+ }
+
@Nullable
@Override
public Language getInjectedLanguage(@NotNull PsiElement context) {
diff --git a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyTemporaryInjector.java b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyTemporaryInjector.java
index 0bbcdef..73c4b21 100644
--- a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyTemporaryInjector.java
+++ b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyTemporaryInjector.java
@@ -5,6 +5,8 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiLanguageInjectionHost;
+import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
+import com.jetbrains.python.codeInsight.PyInjectionUtil;
import com.jetbrains.python.codeInsight.PyInjectorBase;
import org.intellij.plugins.intelliLang.inject.InjectedLanguage;
import org.intellij.plugins.intelliLang.inject.InjectorUtils;
@@ -18,9 +20,13 @@
public class PyTemporaryInjector extends PyInjectorBase {
@Override
public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
- if (registerInjection(registrar, context)) {
+ final PyInjectionUtil.InjectionResult result = registerInjection(registrar, context);
+ if (result.isInjected()) {
final TemporaryPlacesRegistry registry = TemporaryPlacesRegistry.getInstance(context.getProject());
InjectorUtils.registerSupport(registry.getLanguageInjectionSupport(), false, registrar);
+ if (!result.isStrict()) {
+ InjectorUtils.putInjectedFileUserData(registrar, InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
+ }
}
}
diff --git a/python/IntelliLang-python/src/pyInjections.xml b/python/IntelliLang-python/src/pyInjections.xml
index a75015e..fc9207a 100644
--- a/python/IntelliLang-python/src/pyInjections.xml
+++ b/python/IntelliLang-python/src/pyInjections.xml
@@ -9,6 +9,6 @@
</injection>
<injection language="SQL" injector-id="python">
<display-name>"SQL select/delete/insert/update/create"</display-name>
- <place><![CDATA[pyLiteralExpression().withText(string().matchesBrics(".*(((SELECT|DELETE) .*FROM)|((INSERT|REPLACE) .*INTO)|(UPDATE .* SET)|((CREATE|DROP|ALTER) +(TABLE|INDEX))) .*"))]]></place>
+ <place><![CDATA[pyStringLiteralMatches("[ \\t\\r\\n]*(((SELECT|DELETE) .*FROM)|((INSERT|REPLACE) .*INTO)|(UPDATE .* SET)|((CREATE|DROP|ALTER) +(TABLE|INDEX))).*")]]></place>
</injection>
</component>
diff --git a/python/build/resources/logo.bmp b/python/build/resources/logo.bmp
index 19188f3..0f0f82d 100644
--- a/python/build/resources/logo.bmp
+++ b/python/build/resources/logo.bmp
Binary files differ
diff --git a/python/helpers/pycharm/django_test_runner.py b/python/helpers/pycharm/django_test_runner.py
index 7492c5b..ed5fd09 100644
--- a/python/helpers/pycharm/django_test_runner.py
+++ b/python/helpers/pycharm/django_test_runner.py
@@ -1,8 +1,6 @@
-import sys
-
-from tcunittest import TeamcityTestRunner
+from tcunittest import TeamcityTestRunner, TeamcityTestResult
from tcmessages import TeamcityServiceMessages
-
+import sys
from pycharm_run_utils import adjust_django_sys_path
adjust_django_sys_path()
@@ -52,10 +50,41 @@
def __init__(self, stream=sys.stdout, **options):
TeamcityTestRunner.__init__(self, stream)
+
+def strclass(cls):
+ if not cls.__name__:
+ return cls.__module__
+ return "%s.%s" % (cls.__module__, cls.__name__)
+
+class DjangoTeamcityTestResult(TeamcityTestResult):
+ def __init__(self, *args, **kwargs):
+ super(DjangoTeamcityTestResult, self).__init__()
+
+ def _getSuite(self, test):
+ if hasattr(test, "suite"):
+ suite = strclass(test.suite)
+ suite_location = test.suite.location
+ location = test.suite.abs_location
+ if hasattr(test, "lineno"):
+ location = location + ":" + str(test.lineno)
+ else:
+ location = location + ":" + str(test.test.lineno)
+ else:
+
+ suite = strclass(test.__class__)
+ suite_location = "django_testid://" + suite
+ location = "django_testid://" + str(test.id())
+
+ return (suite, location, suite_location)
+
+
class DjangoTeamcityTestRunner(BaseRunner):
def __init__(self, stream=sys.stdout, **options):
super(DjangoTeamcityTestRunner, self).__init__(stream)
+ def _makeResult(self, **kwargs):
+ return DjangoTeamcityTestResult(self.stream, **kwargs)
+
def build_suite(self, *args, **kwargs):
EXCLUDED_APPS = getattr(settings, 'TEST_EXCLUDE', [])
suite = super(DjangoTeamcityTestRunner, self).build_suite(*args, **kwargs)
diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py
index 031d6a1..f7bfb32 100644
--- a/python/helpers/pydev/pydevd.py
+++ b/python/helpers/pydev/pydevd.py
@@ -2,7 +2,6 @@
from django_debug import DjangoLineBreakpoint
from pydevd_signature import SignatureFactory
from pydevd_frame import add_exception_to_frame
-from pydevd_constants import * #@UnusedWildImport
import pydev_imports
from pydevd_breakpoints import * #@UnusedWildImport
import fix_getpass
@@ -1081,6 +1080,9 @@
from imp import new_module
m = new_module('__main__')
sys.modules['__main__'] = m
+ if hasattr(sys.modules['pydevd'], '__loader__'):
+ setattr(m, '__loader__', getattr(sys.modules['pydevd'], '__loader__'))
+
m.__file__ = file
globals = m.__dict__
try:
diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java
index 78752b8..abdfd47 100644
--- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java
+++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkConfigurable.java
@@ -71,6 +71,8 @@
private JPanel myNotificationsPlaceholder;
private PythonPathEditor myPathEditor;
private boolean mySdkListChanged = false;
+ private boolean myMakeActiveAdded = false;
+ private Sdk myAddedSdk;
private final PyConfigurableInterpreterList myInterpreterList;
private final ProjectSdksModel myProjectSdksModel;
private final PyInstalledPackagesPanel myPackagesPanel;
@@ -241,7 +243,8 @@
((PythonSdkAdditionalData)additionalData).associateWithProject(myProject);
}
}
- addCreatedSdk(sdk, true, setAsProjectInterpreter);
+ myMakeActiveAdded = setAsProjectInterpreter;
+ addCreatedSdk(sdk, true);
}
};
final List<Sdk> allSdks = PyConfigurableInterpreterList.getInstance(myProject).getAllPythonSdks();
@@ -288,6 +291,11 @@
myModifiedModificators.clear();
myProjectSdksModel.apply();
mySdkListChanged = false;
+ if (myMakeActiveAdded) {
+ SdkConfigurationUtil.setDirectoryProjectSdk(myProject, myAddedSdk);
+ myProjectSdksModel.setProjectSdk(myAddedSdk);
+ myInterpreterList.setSelectedSdk(myAddedSdk);
+ }
}
/**
@@ -361,13 +369,15 @@
.show(myProject, myProjectSdksModel.getSdks(), button.getPreferredPopupPoint(), false, new NullableConsumer<Sdk>() {
@Override
public void consume(Sdk sdk) {
- addCreatedSdk(sdk, false, false);
+ myMakeActiveAdded = false;
+ addCreatedSdk(sdk, false);
}
});
}
- private void addCreatedSdk(@Nullable final Sdk sdk, boolean newVirtualEnv, boolean makeActive) {
+ private void addCreatedSdk(@Nullable final Sdk sdk, boolean newVirtualEnv) {
if (sdk != null) {
+ myAddedSdk = sdk;
boolean isVirtualEnv = PythonSdkType.isVirtualEnv(sdk);
boolean askSetAsProjectInterpreter = !myProject.isDefault() && !myNewProject;
if (askSetAsProjectInterpreter && isVirtualEnv && !newVirtualEnv) {
@@ -379,7 +389,7 @@
SdkModificator modificator = myModificators.get(sdk);
setSdkAssociated(modificator, !dialog.makeAvailableToAll());
myModifiedModificators.add(modificator);
- makeActive = dialog.useForThisProject();
+ myMakeActiveAdded = dialog.useForThisProject();
}
myProjectSdksModel.addSdk(sdk);
refreshSdkList();
@@ -387,17 +397,12 @@
mySdkListChanged = true;
if (askSetAsProjectInterpreter && !isVirtualEnv && !PythonSdkType.isInvalid(sdk) && !PythonSdkType.isIncompleteRemote(sdk)) {
//TODO: make native mac dialog work
- makeActive = Messages.showIdeaMessageDialog(myProject, "Do you want to set this interpreter as Project Interpreter?",
+ myMakeActiveAdded = Messages.showIdeaMessageDialog(myProject, "Do you want to set this interpreter as Project Interpreter?",
"Project Interpreter",
new String[]{CommonBundle.getYesButtonText(), CommonBundle.getNoButtonText()}, 0, null,
null
) == Messages.YES;
}
- if (makeActive) {
- SdkConfigurationUtil.setDirectoryProjectSdk(myProject, sdk);
- myProjectSdksModel.setProjectSdk(sdk);
- myInterpreterList.setSelectedSdk(sdk);
- }
}
}
diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java
index 94aea767..02176e3 100644
--- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java
+++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java
@@ -148,6 +148,12 @@
return myClass.isValid();
}
+ @Nullable
+ @Override
+ public PyClassLikeType getMetaClassType(@NotNull TypeEvalContext context, boolean inherited) {
+ return null;
+ }
+
public PsiClass getPsiClass() {
return myClass;
}
diff --git a/python/psi-api/src/com/jetbrains/python/PyNames.java b/python/psi-api/src/com/jetbrains/python/PyNames.java
index 81c05df..8e2430e 100644
--- a/python/psi-api/src/com/jetbrains/python/PyNames.java
+++ b/python/psi-api/src/com/jetbrains/python/PyNames.java
@@ -45,7 +45,7 @@
public static final String NEW = "__new__";
public static final String GETATTR = "__getattr__";
public static final String GETATTRIBUTE = "__getattribute__";
- public static final String CLASS = "__class__";
+ public static final String __CLASS__ = "__class__";
public static final String DUNDER_METACLASS = "__metaclass__";
public static final String METACLASS = "metaclass";
public static final String TYPE = "type";
@@ -136,9 +136,9 @@
public static final String COLLECTIONS_NAMEDTUPLE = COLLECTIONS + "." + NAMEDTUPLE;
public static final String FORMAT = "format";
-
- public static final String ABSTRACTMETHOD = "abc.abstractmethod";
- public static final String ABSTRACTPROPERTY = "abc.abstractproperty";
+
+ public static final String ABSTRACTMETHOD = "abstractmethod";
+ public static final String ABSTRACTPROPERTY = "abstractproperty";
public static final String TUPLE = "tuple";
public static final String SET = "set";
@@ -156,7 +156,7 @@
public static final String TEST_CASE = "TestCase";
- public static final String PYCACHE = "__pycache__";
+ public static final String PYCACHE = "__pycache__";
public static final String NOT_IMPLEMENTED_ERROR = "NotImplementedError";
@@ -166,7 +166,7 @@
* Contains all known predefined names of "__foo__" form.
*/
public static ImmutableSet<String> UnderscoredAttributes = ImmutableSet.of(
- "__all__",
+ "__all__",
"__author__",
"__bases__",
"__defaults__",
@@ -227,38 +227,38 @@
.put("__abs__", _only_self_descr)
.put("__add__", _self_other_descr)
.put("__and__", _self_other_descr)
- //_BuiltinMethods.put("__all__", _only_self_descr);
- //_BuiltinMethods.put("__author__", _only_self_descr);
- //_BuiltinMethods.put("__bases__", _only_self_descr);
+ //_BuiltinMethods.put("__all__", _only_self_descr);
+ //_BuiltinMethods.put("__author__", _only_self_descr);
+ //_BuiltinMethods.put("__bases__", _only_self_descr);
.put("__call__", new BuiltinDescription("(self, *args, **kwargs)"))
- //_BuiltinMethods.put("__class__", _only_self_descr);
+ //_BuiltinMethods.put("__class__", _only_self_descr);
.put("__cmp__", _self_other_descr)
.put("__coerce__", _self_other_descr)
.put("__complex__", _only_self_descr)
.put("__contains__", _self_item_descr)
- //_BuiltinMethods.put("__debug__", _only_self_descr);
+ //_BuiltinMethods.put("__debug__", _only_self_descr);
.put("__del__", _only_self_descr)
.put("__delete__", new BuiltinDescription("(self, instance)"))
.put("__delattr__", _self_item_descr)
.put("__delitem__", _self_key_descr)
.put("__delslice__", new BuiltinDescription("(self, i, j)"))
- //_BuiltinMethods.put("__dict__", _only_self_descr);
+ //_BuiltinMethods.put("__dict__", _only_self_descr);
.put("__divmod__", _self_other_descr)
- //_BuiltinMethods.put("__doc__", _only_self_descr);
- //_BuiltinMethods.put("__docformat__", _only_self_descr);
+ //_BuiltinMethods.put("__doc__", _only_self_descr);
+ //_BuiltinMethods.put("__docformat__", _only_self_descr);
.put("__enter__", _only_self_descr)
.put("__exit__", new BuiltinDescription("(self, exc_type, exc_val, exc_tb)"))
.put("__eq__", _self_other_descr)
- //_BuiltinMethods.put("__file__", _only_self_descr);
+ //_BuiltinMethods.put("__file__", _only_self_descr);
.put("__float__", _only_self_descr)
.put("__floordiv__", _self_other_descr)
- //_BuiltinMethods.put("__future__", _only_self_descr);
+ //_BuiltinMethods.put("__future__", _only_self_descr);
.put("__ge__", _self_other_descr)
.put("__get__", new BuiltinDescription("(self, instance, owner)"))
.put("__getattr__", _self_item_descr)
.put("__getattribute__", _self_item_descr)
.put("__getitem__", _self_item_descr)
- //_BuiltinMethods.put("__getslice__", new BuiltinDescription("(self, i, j)"));
+ //_BuiltinMethods.put("__getslice__", new BuiltinDescription("(self, i, j)"));
.put("__gt__", _self_other_descr)
.put("__hash__", _only_self_descr)
.put("__hex__", _only_self_descr)
@@ -266,7 +266,7 @@
.put("__iand__", _self_other_descr)
.put("__idiv__", _self_other_descr)
.put("__ifloordiv__", _self_other_descr)
- //_BuiltinMethods.put("__import__", _only_self_descr);
+ //_BuiltinMethods.put("__import__", _only_self_descr);
.put("__ilshift__", _self_other_descr)
.put("__imod__", _self_other_descr)
.put("__imul__", _self_other_descr)
@@ -286,18 +286,18 @@
.put("__long__", _only_self_descr)
.put("__lshift__", _self_other_descr)
.put("__lt__", _self_other_descr)
- //_BuiltinMethods.put("__members__", _only_self_descr);
- //_BuiltinMethods.put("__metaclass__", _only_self_descr);
+ //_BuiltinMethods.put("__members__", _only_self_descr);
+ //_BuiltinMethods.put("__metaclass__", _only_self_descr);
.put("__mod__", _self_other_descr)
- //_BuiltinMethods.put("__mro__", _only_self_descr);
+ //_BuiltinMethods.put("__mro__", _only_self_descr);
.put("__mul__", _self_other_descr)
- //_BuiltinMethods.put("__name__", _only_self_descr);
+ //_BuiltinMethods.put("__name__", _only_self_descr);
.put("__ne__", _self_other_descr)
.put("__neg__", _only_self_descr)
.put(NEW, new BuiltinDescription("(cls, *args, **kwargs)"))
.put("__oct__", _only_self_descr)
.put("__or__", _self_other_descr)
- //_BuiltinMethods.put("__path__", _only_self_descr);
+ //_BuiltinMethods.put("__path__", _only_self_descr);
.put("__pos__", _only_self_descr)
.put("__pow__", new BuiltinDescription("(self, power, modulo=None)"))
.put("__radd__", _self_other_descr)
@@ -322,13 +322,13 @@
.put("__setattr__", new BuiltinDescription("(self, key, value)"))
.put("__setitem__", new BuiltinDescription("(self, key, value)"))
.put("__setslice__", new BuiltinDescription("(self, i, j, sequence)"))
- //_BuiltinMethods.put("__self__", _only_self_descr);
- //_BuiltinMethods.put("__slots__", _only_self_descr);
+ //_BuiltinMethods.put("__self__", _only_self_descr);
+ //_BuiltinMethods.put("__slots__", _only_self_descr);
.put("__str__", _only_self_descr)
.put("__sub__", _self_other_descr)
.put("__truediv__", _self_other_descr)
.put("__unicode__", _only_self_descr)
- //_BuiltinMethods.put("__version__", _only_self_descr);
+ //_BuiltinMethods.put("__version__", _only_self_descr);
.put("__xor__", _self_other_descr)
.build();
@@ -355,56 +355,92 @@
public static final String CANONICAL_CLS = "cls";
public static final String BASESTRING = "basestring";
+ /*
+ Python keywords
+ */
+
+ public static final String CLASS = "class";
+ public static final String DEF = "def";
+ public static final String IF = "if";
+ public static final String ELSE = "else";
+ public static final String ELIF = "elif";
+ public static final String TRY = "try";
+ public static final String EXCEPT = "except";
+ public static final String FINALLY = "finally";
+ public static final String WHILE = "while";
+ public static final String FOR = "for";
+ public static final String WITH = "with";
+ public static final String AS = "as";
+ public static final String ASSERT = "assert";
+ public static final String DEL = "del";
+ public static final String EXEC = "exec";
+ public static final String FROM = "from";
+ public static final String IMPORT = "import";
+ public static final String RAISE = "raise";
+ public static final String PRINT = "print";
+ public static final String BREAK = "break";
+ public static final String CONTINUE = "continue";
+ public static final String GLOBAL = "global";
+ public static final String RETURN = "return";
+ public static final String YIELD = "yield";
+ public static final String NONLOCAL = "nonlocal";
+ public static final String AND = "and";
+ public static final String OR = "or";
+ public static final String IS = "is";
+ public static final String IN = "in";
+ public static final String NOT = "not";
+ public static final String LAMBDA = "lambda";
+
/**
* Contains keywords as of CPython 2.5.
*/
public static ImmutableSet<String> Keywords = ImmutableSet.of(
- "and",
- "del",
- "from",
- "not",
- "while",
- "as",
- "elif",
- "global",
- "or",
- "with",
- "assert",
- "else",
- "if",
- "pass",
- "yield",
- "break",
- "except",
- "import",
- "print",
- "class",
- "exec",
- "in",
- "raise",
- "continue",
- "finally",
- "is",
- "return",
- "def",
- "for",
- "lambda",
- "try"
+ AND,
+ DEL,
+ FROM,
+ NOT,
+ WHILE,
+ AS,
+ ELIF,
+ GLOBAL,
+ OR,
+ WITH,
+ ASSERT,
+ ELSE,
+ IF,
+ PASS,
+ YIELD,
+ BREAK,
+ EXCEPT,
+ IMPORT,
+ PRINT,
+ __CLASS__,
+ EXEC,
+ IN,
+ RAISE,
+ CONTINUE,
+ FINALLY,
+ IS,
+ RETURN,
+ DEF,
+ FOR,
+ LAMBDA,
+ TRY
);
public static Set<String> BuiltinInterfaces = ImmutableSet.of(
- CALLABLE, HASHABLE, ITERABLE, ITERATOR, SIZED, CONTAINER, SEQUENCE, MAPPING, ABC_COMPLEX, ABC_REAL, ABC_RATIONAL, ABC_INTEGRAL,
- ABC_NUMBER
+ CALLABLE, HASHABLE, ITERABLE, ITERATOR, SIZED, CONTAINER, SEQUENCE, MAPPING, ABC_COMPLEX, ABC_REAL, ABC_RATIONAL, ABC_INTEGRAL,
+ ABC_NUMBER
);
/**
* TODO: dependency on language level.
+ *
* @param name what to check
* @return true iff the name is either a keyword or a reserved name, like None.
- *
*/
public static boolean isReserved(@NonNls String name) {
- return Keywords.contains(name) || NONE.equals(name) || "as".equals(name) || "with".equals(name);
+ return Keywords.contains(name) || NONE.equals(name);
}
// NOTE: includes unicode only good for py3k
@@ -412,6 +448,7 @@
/**
* TODO: dependency on language level.
+ *
* @param name what to check
* @return true iff name is not reserved and is a well-formed identifier.
*/
diff --git a/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java b/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java
index 0dbf909..a344e89 100644
--- a/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java
+++ b/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java
@@ -37,6 +37,7 @@
private String myName;
private final boolean myResolveToInstance;
private final Function<PsiElement, PyType> myTypeCallback;
+ @Nullable
private final String myTypeName;
private final PsiElement myTarget;
@@ -44,7 +45,7 @@
boolean myFunction = false;
- public PyDynamicMember(@NotNull final String name, @NotNull final String type, final boolean resolveToInstance) {
+ public PyDynamicMember(@NotNull final String name, @Nullable final String type, final boolean resolveToInstance) {
myName = name;
myResolveToInstance = resolveToInstance;
myTypeName = type;
@@ -63,7 +64,7 @@
}
public PyDynamicMember(@NotNull final String name,
- @NotNull final String type,
+ @Nullable final String type,
final Function<PsiElement, PyType> typeCallback) {
myName = name;
diff --git a/python/psi-api/src/com/jetbrains/python/psi/NameDefiner.java b/python/psi-api/src/com/jetbrains/python/psi/NameDefiner.java
index 08c7aa5..3145b8e 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/NameDefiner.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/NameDefiner.java
@@ -58,7 +58,7 @@
for (PyElement elt : it) {
if (elt != null) {
// qualified refs don't match by last name, and we're not checking FQNs here
- if (elt instanceof PyQualifiedExpression && ((PyQualifiedExpression)elt).getQualifier() != null) continue;
+ if (elt instanceof PyQualifiedExpression && ((PyQualifiedExpression)elt).isQualified()) continue;
if (name.equals(elt.getName())) { // plain name matches
ret = elt;
break;
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java
index 6bad8d1..53dd81a 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java
@@ -218,4 +218,19 @@
boolean processClassLevelDeclarations(@NotNull PsiScopeProcessor processor);
boolean processInstanceLevelDeclarations(@NotNull PsiScopeProcessor processor, @Nullable PsiElement location);
+
+ /**
+ * Returns the type representing the metaclass of the class if it is explicitly set, null otherwise.
+ */
+ @Nullable
+ PyClassLikeType getMetaClassType(@NotNull TypeEvalContext context);
+
+ /**
+ * Returns the expression that defines the metaclass of the class.
+ *
+ * It might be defined outside the class in case of file-level __metaclass__ attributes.
+ * Operates at the AST level.
+ */
+ @Nullable
+ PyExpression getMetaClassExpression();
}
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java
index 012ed41..995ad30 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyQualifiedExpression.java
@@ -17,6 +17,7 @@
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiPolyVariantReference;
+import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -31,6 +32,19 @@
PyExpression getQualifier();
/**
+ * Checks if the expression is qualified.
+ *
+ * Unlike {@link #getQualifier()}, it may not require AST access.
+ */
+ boolean isQualified();
+
+ /**
+ * Returns the qualified name for the expression if all the qualifiers are qualified expressions.
+ */
+ @Nullable
+ QualifiedName asQualifiedName();
+
+ /**
* Returns the name to the right of the qualifier.
*
* @return the name referenced by the expression.
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java
index a8fd0a9..c1f7e8d 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyReferenceExpression.java
@@ -16,11 +16,9 @@
package com.jetbrains.python.psi;
import com.intellij.psi.PsiPolyVariantReference;
-import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.QualifiedResolveResult;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/**
* @author yole
@@ -40,9 +38,6 @@
@NotNull
QualifiedResolveResult followAssignmentsChain(PyResolveContext resolveContext);
- @Nullable
- QualifiedName asQualifiedName();
-
@NotNull
PsiPolyVariantReference getReference();
}
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java
index 0a12224..dc3f28d 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PySubscriptionExpression.java
@@ -15,12 +15,21 @@
*/
package com.jetbrains.python.psi;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public interface PySubscriptionExpression extends PyQualifiedExpression, PyReferenceOwner {
+
+ /**
+ * @return For <code>spam[x][y][n]</code> will return <code>spam</code> regardless number of its dimensions
+ */
+ @NotNull
+ PyExpression getRootOperand();
+
+ @NotNull
PyExpression getOperand();
@Nullable
diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyTargetExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyTargetExpression.java
index fd028d6..0b67d85 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PyTargetExpression.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyTargetExpression.java
@@ -57,6 +57,4 @@
@Nullable
PyClass getContainingClass();
-
- boolean isQualified();
}
diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java
index c8433aa..b3a1134 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java
@@ -23,6 +23,7 @@
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.QualifiedName;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyTokenTypes;
@@ -32,6 +33,7 @@
import java.lang.reflect.Array;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
/**
@@ -375,6 +377,65 @@
return element.getTextOffset() <= element2.getTextOffset();
}
+ @Nullable
+ public static QualifiedName asQualifiedName(@Nullable PyExpression expr) {
+ return expr instanceof PyQualifiedExpression ? ((PyQualifiedExpression)expr).asQualifiedName() : null;
+ }
+
+ @Nullable
+ public static PyExpression getFirstQualifier(@NotNull PyQualifiedExpression expr) {
+ final List<PyExpression> expressions = unwindQualifiers(expr);
+ if (!expressions.isEmpty()) {
+ return expressions.get(0);
+ }
+ return null;
+ }
+
+ @NotNull
+ public static String toPath(@Nullable PyQualifiedExpression expr) {
+ if (expr != null) {
+ final QualifiedName qName = expr.asQualifiedName();
+ if (qName != null) {
+ return qName.toString();
+ }
+ final String name = expr.getName();
+ if (name != null) {
+ return name;
+ }
+ }
+ return "";
+ }
+
+ @Nullable
+ protected static QualifiedName asQualifiedName(@NotNull PyQualifiedExpression expr) {
+ return fromReferenceChain(unwindQualifiers(expr));
+ }
+
+ @NotNull
+ private static List<PyExpression> unwindQualifiers(@NotNull final PyQualifiedExpression expr) {
+ final List<PyExpression> path = new LinkedList<PyExpression>();
+ PyQualifiedExpression e = expr;
+ while (e != null) {
+ path.add(0, e);
+ final PyExpression q = e.getQualifier();
+ e = q instanceof PyQualifiedExpression ? (PyQualifiedExpression)q : null;
+ }
+ return path;
+ }
+
+ @Nullable
+ private static QualifiedName fromReferenceChain(@NotNull List<PyExpression> components) {
+ final List<String> componentNames = new ArrayList<String>(components.size());
+ for (PyExpression component : components) {
+ final String refName = (component instanceof PyQualifiedExpression) ? ((PyQualifiedExpression)component).getReferencedName() : null;
+ if (refName == null) {
+ return null;
+ }
+ componentNames.add(refName);
+ }
+ return QualifiedName.fromComponents(componentNames);
+ }
+
private static abstract class TopLevelVisitor extends PyRecursiveElementVisitor {
public void visitPyElement(final PyElement node) {
super.visitPyElement(node);
diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyQualifiedNameFactory.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyQualifiedNameFactory.java
deleted file mode 100644
index b26d445..0000000
--- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyQualifiedNameFactory.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2000-2013 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.psi.impl;
-
-import com.intellij.psi.util.QualifiedName;
-import com.jetbrains.python.psi.PyExpression;
-import com.jetbrains.python.psi.PyQualifiedExpression;
-import com.jetbrains.python.psi.PyReferenceExpression;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author yole
- */
-public class PyQualifiedNameFactory {
- @Nullable
- public static QualifiedName fromReferenceChain(List<PyExpression> components) {
- List<String> componentNames = new ArrayList<String>(components.size());
- for (PyExpression component : components) {
- final String refName = (component instanceof PyQualifiedExpression) ? ((PyQualifiedExpression)component).getReferencedName() : null;
- if (refName == null) {
- return null;
- }
- componentNames.add(refName);
- }
- return QualifiedName.fromComponents(componentNames);
- }
-
- @Nullable
- public static QualifiedName fromExpression(PyExpression expr) {
- return expr instanceof PyReferenceExpression ? ((PyReferenceExpression) expr).asQualifiedName() : null;
- }
-}
diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java
index b4e5be8..ff188f5 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/impl/PyTypeProvider.java
@@ -42,9 +42,6 @@
PyType getReturnType(@NotNull PyFunction function, @Nullable PyQualifiedExpression callSite, @NotNull TypeEvalContext context);
@Nullable
- PyType getIterationType(@NotNull PyClass iterable);
-
- @Nullable
PyType getContextManagerVariableType(PyClass contextManager, PyExpression withExpression, TypeEvalContext context);
@Nullable
diff --git a/python/psi-api/src/com/jetbrains/python/psi/stubs/PyClassStub.java b/python/psi-api/src/com/jetbrains/python/psi/stubs/PyClassStub.java
index 02b212c..2ca1e2a 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/stubs/PyClassStub.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/stubs/PyClassStub.java
@@ -20,13 +20,15 @@
package com.jetbrains.python.psi.stubs;
import com.intellij.psi.stubs.NamedStub;
-import com.jetbrains.python.psi.PyClass;
import com.intellij.psi.util.QualifiedName;
+import com.jetbrains.python.psi.PyClass;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface PyClassStub extends NamedStub<PyClass> {
QualifiedName[] getSuperClasses();
+ @Nullable QualifiedName getMetaClass();
List<String> getSlots();
String getDocString();
}
\ No newline at end of file
diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java
index 804195a..a059bc7 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java
@@ -44,4 +44,7 @@
boolean inherited);
boolean isValid();
+
+ @Nullable
+ PyClassLikeType getMetaClassType(@NotNull TypeEvalContext context, boolean inherited);
}
diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java
index 0792b50..6330c4a 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java
@@ -106,11 +106,6 @@
return null;
}
- @Override
- public PyType getIterationType(@NotNull PyClass iterable) {
- return null;
- }
-
@Nullable
@Override
public PyType getContextManagerVariableType(PyClass contextManager, PyExpression withExpression, TypeEvalContext context) {
diff --git a/python/resources/idea/PyCharmCoreApplicationInfo.xml b/python/resources/idea/PyCharmCoreApplicationInfo.xml
index 0ac5772..3e6d9a6 100644
--- a/python/resources/idea/PyCharmCoreApplicationInfo.xml
+++ b/python/resources/idea/PyCharmCoreApplicationInfo.xml
@@ -1,6 +1,6 @@
<component>
<company name="JetBrains s.r.o." url="http://www.jetbrains.com/?fromIDE"/>
- <version major="3" minor="1" eap="true"/>
+ <version major="3" minor="1" eap="false"/>
<build number="__BUILD_NUMBER__" date="__BUILD_DATE__"/>
<logo url="/pycharm_core_logo.png" textcolor="ffffff" progressColor="ffaa16" progressY="230" progressTailIcon="/community_progress_tail.png"/>
<about url="/pycharm_core_about.png" logoX="300" logoY="265" logoW="75" logoH="30" foreground="ffffff" linkColor="fca11a"/>
diff --git a/python/resources/inspectionDescriptions/PyAssignmentToLoopOrWithParameterInspection.html b/python/resources/inspectionDescriptions/PyAssignmentToLoopOrWithParameterInspection.html
new file mode 100644
index 0000000..4fc3dcd
--- /dev/null
+++ b/python/resources/inspectionDescriptions/PyAssignmentToLoopOrWithParameterInspection.html
@@ -0,0 +1,21 @@
+<html>
+<body>
+<span style="font-family: verdana,serif;">
+ Checks for cases when you rewrite loop variable with inner loop
+</span>
+<pre style="font-family: monospace">
+ for i in xrange(5):
+ for i in xrange(20, 25):
+ print("Inner", i)
+ print("Outer", i)
+ </pre>
+<span style="font-family: verdana,serif;">
+ It also warns you if variable declared in <code>with</code> statement is redeclared inside of statement body:
+</span>
+<pre style="font-family: monospace">
+ with open("file") as f:
+ f.read()
+ with open("file") as f:
+ </pre>
+</body>
+</html>
diff --git a/python/resources/pycharm_core_about.png b/python/resources/pycharm_core_about.png
index 9a1bb9f..b9fa97f 100644
--- a/python/resources/pycharm_core_about.png
+++ b/python/resources/pycharm_core_about.png
Binary files differ
diff --git a/python/resources/pycharm_core_about@2x.png b/python/resources/pycharm_core_about@2x.png
index c860c60..c58e5a3 100644
--- a/python/resources/pycharm_core_about@2x.png
+++ b/python/resources/pycharm_core_about@2x.png
Binary files differ
diff --git a/python/resources/pycharm_core_logo.png b/python/resources/pycharm_core_logo.png
index 228dfdd..632185d 100644
--- a/python/resources/pycharm_core_logo.png
+++ b/python/resources/pycharm_core_logo.png
Binary files differ
diff --git a/python/resources/pycharm_core_logo@2x.png b/python/resources/pycharm_core_logo@2x.png
index f45960d..df1382a 100644
--- a/python/resources/pycharm_core_logo@2x.png
+++ b/python/resources/pycharm_core_logo@2x.png
Binary files differ
diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml
index 708a686..6c4665d 100644
--- a/python/src/META-INF/python-core.xml
+++ b/python/src/META-INF/python-core.xml
@@ -114,6 +114,7 @@
<runConfigurationProducer implementation="com.jetbrains.python.testing.unittest.PythonUnitTestConfigurationProducer"/>
<testSrcLocator implementation="com.jetbrains.python.testing.PythonUnitTestTestIdUrlProvider"/>
+ <testSrcLocator implementation="com.jetbrains.django.testRunner.DjangoTestTestIdUrlProvider"/>
<testSrcLocator implementation="com.jetbrains.python.testing.nosetest.PythonNoseTestUrlProvider"/>
<runConfigurationProducer implementation="com.jetbrains.python.testing.pytest.PyTestConfigurationProducer"/>
@@ -329,6 +330,7 @@
<localInspection language="Python" shortName="PyShadowingNamesInspection" displayName="Shadowing names from outer scopes" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyShadowingNamesInspection"/>
<localInspection language="Python" shortName="PyAbstractClassInspection" displayName="Class must implement all abstract methods" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyAbstractClassInspection"/>
<localInspection language="Python" shortName="PyPep8NamingInspection" displayName="PEP 8 naming convention violation" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyPep8NamingInspection"/>
+ <localInspection language="Python" shortName="PyAssignmentToLoopOrWithParameterInspection" displayName="Assignment to 'for' loop or 'with' statement parameter" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyAssignmentToLoopOrWithParameterInspection"/>
<liveTemplateContext implementation="com.jetbrains.python.codeInsight.liveTemplates.PythonTemplateContextType"/>
<liveTemplateMacro implementation="com.jetbrains.python.codeInsight.liveTemplates.CollectionElementNameMacro"/>
diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties
index 84d4c6d..c8755a0 100644
--- a/python/src/com/jetbrains/python/PyBundle.properties
+++ b/python/src/com/jetbrains/python/PyBundle.properties
@@ -511,6 +511,10 @@
INSP.NAME.global.undefined=Global variable is undefined at the module level
INSP.NAME.global.$0.undefined=Global variable ''{0}'' is undefined at the module level
+#PyAssignmentToLoopOrWithParameterInspection
+INSP.NAME.assignment.to.loop.or.with.parameter.display.name=Assignment to 'for' loop or 'with' statement parameter
+INSP.NAME.assignment.to.loop.or.with.parameter.display.message=Variable ''{0}'' already declared in ''for'' loop or ''with'' statement above
+
# Refactoring
# introduce
refactoring.introduce.name.error=Incorrect name
@@ -585,26 +589,26 @@
refactoring.change.signature.error.wrong.caret.position.method.name=The caret should be positioned at the name of the method to be refactored.
### 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=can't assign to list comprehension
-ANN.cant.assign.to.dict.comprh=can't assign to dict comprehension
-ANN.cant.assign.to.set.comprh=can't assign to set comprehension
-ANN.cant.aug.assign.to.comprh=augmented assign to list comprehension not possible
-ANN.cant.aug.assign.to.dict.comprh=augmented assign to dict comprehension not possible
-ANN.cant.aug.assign.to.set.comprh=augmented assign to set comprehension not possible
-ANN.cant.assign.to.literal=can't assign to literal
-ANN.cant.delete.literal=can't delete literal
-ANN.cant.assign.to.lambda=can't assign to lambda
+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=Can't assign to list comprehension
+ANN.cant.assign.to.dict.comprh=Can't assign to dict comprehension
+ANN.cant.assign.to.set.comprh=Can't assign to set comprehension
+ANN.cant.aug.assign.to.comprh=Augmented assign to list comprehension not possible
+ANN.cant.aug.assign.to.dict.comprh=Augmented assign to dict comprehension not possible
+ANN.cant.aug.assign.to.set.comprh=Augmented assign to set comprehension not possible
+ANN.cant.assign.to.literal=Can't assign to literal
+ANN.cant.delete.literal=Can't delete 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
diff --git a/python/src/com/jetbrains/python/codeInsight/PyContainerProvider.java b/python/src/com/jetbrains/python/codeInsight/PyContainerProvider.java
new file mode 100644
index 0000000..11a3fe5
--- /dev/null
+++ b/python/src/com/jetbrains/python/codeInsight/PyContainerProvider.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.codeInsight;
+
+import com.intellij.codeInsight.ContainerProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.StubBasedPsiElement;
+import com.intellij.psi.stubs.StubElement;
+import com.jetbrains.python.psi.PyElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author vlan
+ */
+public class PyContainerProvider implements ContainerProvider {
+ @Nullable
+ @Override
+ public PsiElement getContainer(@NotNull PsiElement item) {
+ if (item instanceof PyElement && item instanceof StubBasedPsiElement) {
+ return getContainerByStub((StubBasedPsiElement)item);
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PsiElement getContainerByStub(@NotNull StubBasedPsiElement element) {
+ final StubElement stub = element.getStub();
+ if (stub != null) {
+ final StubElement parentStub = stub.getParentStub();
+ if (parentStub != null) {
+ return parentStub.getPsi();
+ }
+ }
+ return null;
+ }
+}
diff --git a/python/src/com/jetbrains/python/codeInsight/PyInjectionUtil.java b/python/src/com/jetbrains/python/codeInsight/PyInjectionUtil.java
index 9a7edad..fe51d64 100644
--- a/python/src/com/jetbrains/python/codeInsight/PyInjectionUtil.java
+++ b/python/src/com/jetbrains/python/codeInsight/PyInjectionUtil.java
@@ -32,6 +32,31 @@
* @author vlan
*/
public class PyInjectionUtil {
+
+ public static class InjectionResult {
+ public static InjectionResult EMPTY = new InjectionResult(false, true);
+
+ private final boolean myInjected;
+ private final boolean myStrict;
+
+ private InjectionResult(boolean injected, boolean strict) {
+ myInjected = injected;
+ myStrict = strict;
+ }
+
+ public boolean isInjected() {
+ return myInjected;
+ }
+
+ public boolean isStrict() {
+ return myStrict;
+ }
+
+ public InjectionResult append(@NotNull InjectionResult result) {
+ return new InjectionResult(myInjected || result.isInjected(), myStrict && result.isStrict());
+ }
+ }
+
public static final List<Class<? extends PyExpression>> ELEMENTS_TO_INJECT_IN =
Arrays.asList(PyStringLiteralExpression.class, PyParenthesizedExpression.class, PyBinaryExpression.class, PyCallExpression.class);
@@ -54,8 +79,10 @@
* Registers language injections in the given registrar for the specified string literal element or its ancestor that contains
* string concatenations or formatting.
*/
- public static void registerStringLiteralInjection(@NotNull PsiElement element, @NotNull MultiHostRegistrar registrar) {
- processStringLiteral(element, registrar, "", "", Formatting.PERCENT);
+ @NotNull
+ public static InjectionResult registerStringLiteralInjection(@NotNull PsiElement element, @NotNull MultiHostRegistrar registrar) {
+ // Assume percent formatting since the MySQL parser cannot handle Python-style substitutions
+ return processStringLiteral(element, registrar, "", "", Formatting.PERCENT);
}
private static boolean isStringLiteralPart(@NotNull PsiElement element, @Nullable PsiElement context) {
@@ -101,10 +128,13 @@
return null;
}
- private static void processStringLiteral(@NotNull PsiElement element, @NotNull MultiHostRegistrar registrar, @NotNull String prefix,
- @NotNull String suffix, @NotNull Formatting formatting) {
- final String missingValue = "missing";
+ @NotNull
+ private static InjectionResult processStringLiteral(@NotNull PsiElement element, @NotNull MultiHostRegistrar registrar,
+ @NotNull String prefix, @NotNull String suffix, @NotNull Formatting formatting) {
+ final String missingValue = "missing_value";
if (element instanceof PyStringLiteralExpression) {
+ boolean injected = false;
+ boolean strict = true;
final PyStringLiteralExpression expr = (PyStringLiteralExpression)element;
final List<TextRange> ranges = expr.getStringValueTextRanges();
final String text = expr.getText();
@@ -112,6 +142,9 @@
if (formatting != Formatting.NONE) {
final String part = range.substring(text);
final List<FormatStringChunk> chunks = formatting == Formatting.NEW_STYLE ? parseNewStyleFormat(part) : parsePercentFormat(part);
+ if (!filterSubstitutions(chunks).isEmpty()) {
+ strict = false;
+ }
for (int i = 0; i < chunks.size(); i++) {
final FormatStringChunk chunk = chunks.get(i);
if (chunk instanceof ConstantChunk) {
@@ -137,18 +170,21 @@
}
final TextRange chunkRange = chunk.getTextRange().shiftRight(range.getStartOffset());
registrar.addPlace(chunkPrefix, chunkSuffix, expr, chunkRange);
+ injected = true;
}
}
}
else {
registrar.addPlace(prefix, suffix, expr, range);
+ injected = true;
}
}
+ return new InjectionResult(injected, strict);
}
else if (element instanceof PyParenthesizedExpression) {
final PyExpression contained = ((PyParenthesizedExpression)element).getContainedExpression();
if (contained != null) {
- processStringLiteral(contained, registrar, prefix, suffix, formatting);
+ return processStringLiteral(contained, registrar, prefix, suffix, formatting);
}
}
else if (element instanceof PyBinaryExpression) {
@@ -158,23 +194,26 @@
final boolean isLeftString = isStringLiteralPart(left, null);
if (expr.isOperator("+")) {
final boolean isRightString = right != null && isStringLiteralPart(right, null);
+ InjectionResult result = InjectionResult.EMPTY;
if (isLeftString) {
- processStringLiteral(left, registrar, prefix, isRightString ? "" : missingValue, formatting);
+ result = result.append(processStringLiteral(left, registrar, prefix, isRightString ? "" : missingValue, formatting));
}
if (isRightString) {
- processStringLiteral(right, registrar, isLeftString ? "" : missingValue, suffix, formatting);
+ result = result.append(processStringLiteral(right, registrar, isLeftString ? "" : missingValue, suffix, formatting));
}
+ return result;
}
else if (expr.isOperator("%")) {
- processStringLiteral(left, registrar, prefix, suffix, Formatting.PERCENT);
+ return processStringLiteral(left, registrar, prefix, suffix, Formatting.PERCENT);
}
}
else if (element instanceof PyCallExpression) {
final PyExpression qualifier = getFormatCallQualifier((PyCallExpression)element);
if (qualifier != null) {
- processStringLiteral(qualifier, registrar, prefix, suffix, Formatting.NEW_STYLE);
+ return processStringLiteral(qualifier, registrar, prefix, suffix, Formatting.NEW_STYLE);
}
}
+ return InjectionResult.EMPTY;
}
private enum Formatting {
diff --git a/python/src/com/jetbrains/python/codeInsight/PyInjectorBase.java b/python/src/com/jetbrains/python/codeInsight/PyInjectorBase.java
index 98ae8c4..4fd2560 100644
--- a/python/src/com/jetbrains/python/codeInsight/PyInjectorBase.java
+++ b/python/src/com/jetbrains/python/codeInsight/PyInjectorBase.java
@@ -27,17 +27,19 @@
@Nullable
public abstract Language getInjectedLanguage(@NotNull PsiElement context);
- protected boolean registerInjection(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
+ protected PyInjectionUtil.InjectionResult registerInjection(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
final Language language = getInjectedLanguage(context);
if (language != null) {
final PsiElement element = PyInjectionUtil.getLargestStringLiteral(context);
if (element != null) {
registrar.startInjecting(language);
- PyInjectionUtil.registerStringLiteralInjection(element, registrar);
- registrar.doneInjecting();
- return true;
+ final PyInjectionUtil.InjectionResult result = PyInjectionUtil.registerStringLiteralInjection(element, registrar);
+ if (result.isInjected()) {
+ registrar.doneInjecting();
+ }
+ return result;
}
}
- return false;
+ return PyInjectionUtil.InjectionResult.EMPTY;
}
}
diff --git a/python/src/com/jetbrains/python/codeInsight/PyKeywords.java b/python/src/com/jetbrains/python/codeInsight/PyKeywords.java
deleted file mode 100644
index 458715f..0000000
--- a/python/src/com/jetbrains/python/codeInsight/PyKeywords.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.codeInsight;
-
-/**
- * @author traff
- */
-public class PyKeywords {
- public static final String DEF = "def";
- public static final String CLASS = "class";
-
- public static final String IF = "if";
- public static final String ELSE = "else";
- public static final String ELIF = "elif";
-
- public static final String TRY = "try";
- public static final String EXCEPT = "except";
- public static final String FINALLY = "finally";
-
- public static final String WHILE = "while";
-
- public static final String FOR = "for";
- public static final String WITH = "with";
- public static final String AS = "as";
-
- public static final String ASSERT = "assert";
- public static final String DEL = "del";
- public static final String EXEC = "exec";
- public static final String FROM = "from";
- public static final String IMPORT = "import";
- public static final String RAISE = "raise";
- public static final String PRINT = "print";
- public static final String BREAK = "break";
- public static final String CONTINUE = "continue";
- public static final String GLOBAL = "global";
- public static final String RETURN = "return";
- public static final String YIELD = "yield";
- public static final String NONLOCAL = "nonlocal";
-
- public static final String AND = "and";
- public static final String OR = "or";
- public static final String IS = "is";
- public static final String IN = "in";
- public static final String NOT = "not";
-
- public static final String LAMBDA = "lambda";
-
- public static final String TRUE = "True";
- public static final String FALSE = "False";
- public static final String NONE = "None";
-}
diff --git a/python/src/com/jetbrains/python/codeInsight/PyUnindentingInsertHandler.java b/python/src/com/jetbrains/python/codeInsight/PyUnindentingInsertHandler.java
index c6a69d7..d932d71 100644
--- a/python/src/com/jetbrains/python/codeInsight/PyUnindentingInsertHandler.java
+++ b/python/src/com/jetbrains/python/codeInsight/PyUnindentingInsertHandler.java
@@ -25,6 +25,7 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.completion.PythonLookupElement;
import com.jetbrains.python.psi.PyStatementWithElse;
import com.jetbrains.python.psi.PyTryExceptStatement;
@@ -67,28 +68,28 @@
Class<? extends PsiElement> parentClass = null;
- int last_offset = nonspace_offset + PyKeywords.FINALLY.length(); // the longest of all
+ int last_offset = nonspace_offset + PyNames.FINALLY.length(); // the longest of all
if (last_offset > offset) last_offset = offset;
int local_length = last_offset - nonspace_offset + 1;
if (local_length > 0) {
String piece = text.subSequence(nonspace_offset, last_offset + 1).toString();
- final int else_len = PyKeywords.ELSE.length();
+ final int else_len = PyNames.ELSE.length();
if (local_length >= else_len) {
- if ((piece.startsWith(PyKeywords.ELSE) || piece.startsWith(PyKeywords.ELIF)) &&
+ if ((piece.startsWith(PyNames.ELSE) || piece.startsWith(PyNames.ELIF)) &&
(else_len == piece.length() || piece.charAt(else_len) < 'a' || piece.charAt(else_len) > 'z')) {
parentClass = PyStatementWithElse.class;
}
}
- final int except_len = PyKeywords.EXCEPT.length();
+ final int except_len = PyNames.EXCEPT.length();
if (local_length >= except_len) {
- if (piece.startsWith(PyKeywords.EXCEPT) &&
+ if (piece.startsWith(PyNames.EXCEPT) &&
(except_len == piece.length() || piece.charAt(except_len) < 'a' || piece.charAt(except_len) > 'z')) {
parentClass = PyTryExceptStatement.class;
}
}
- final int finally_len = PyKeywords.FINALLY.length();
+ final int finally_len = PyNames.FINALLY.length();
if (local_length >= finally_len) {
- if (piece.startsWith(PyKeywords.FINALLY) &&
+ if (piece.startsWith(PyNames.FINALLY) &&
(finally_len == piece.length() || piece.charAt(finally_len) < 'a' || piece.charAt(finally_len) > 'z')) {
parentClass = PyTryExceptStatement.class;
}
diff --git a/python/src/com/jetbrains/python/codeInsight/completion/OverwriteEqualsInsertHandler.java b/python/src/com/jetbrains/python/codeInsight/completion/OverwriteEqualsInsertHandler.java
index 1fb1070..e70d1e6 100644
--- a/python/src/com/jetbrains/python/codeInsight/completion/OverwriteEqualsInsertHandler.java
+++ b/python/src/com/jetbrains/python/codeInsight/completion/OverwriteEqualsInsertHandler.java
@@ -34,7 +34,7 @@
}
Document doc = context.getDocument();
int tailOffset = context.getTailOffset();
- if (doc.getCharsSequence().charAt(tailOffset) == '=') {
+ if (tailOffset < doc.getCharsSequence().length() && doc.getCharsSequence().charAt(tailOffset) == '=') {
doc.deleteString(tailOffset, tailOffset+1);
}
}
diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java
index 7725203c..2b466d9 100644
--- a/python/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java
+++ b/python/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java
@@ -54,7 +54,7 @@
if (parameters.isExtendedCompletion()) {
final PsiElement element = parameters.getPosition();
final PsiElement parent = element.getParent();
- if (parent instanceof PyReferenceExpression && ((PyReferenceExpression)parent).getQualifier() != null) {
+ if (parent instanceof PyReferenceExpression && ((PyReferenceExpression)parent).isQualified()) {
return;
}
if (parent instanceof PyStringLiteralExpression) {
diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java
index 6d72024..ed6f2e3 100644
--- a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java
+++ b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java
@@ -33,7 +33,6 @@
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonLanguage;
-import com.jetbrains.python.codeInsight.PyKeywords;
import com.jetbrains.python.codeInsight.PyUnindentingInsertHandler;
import com.jetbrains.python.documentation.doctest.PyDocstringFile;
import com.jetbrains.python.psi.*;
@@ -287,9 +286,9 @@
psiElement()
.inside(PyConditionalStatementPart.class)
.andOr(
- psiElement().afterLeaf(psiElement().withText(PyKeywords.IF)),
- psiElement().afterLeaf(psiElement().withText(PyKeywords.ELIF)),
- psiElement().afterLeaf(psiElement().withText(PyKeywords.WHILE))
+ psiElement().afterLeaf(psiElement().withText(PyNames.IF)),
+ psiElement().afterLeaf(psiElement().withText(PyNames.ELIF)),
+ psiElement().afterLeaf(psiElement().withText(PyNames.WHILE))
);
private static final PsiElementPattern.Capture<PsiElement> IN_IMPORT_STMT =
@@ -309,6 +308,9 @@
private static final PsiElementPattern.Capture<PsiElement> IN_EXCEPT_BODY =
psiElement().inside(psiElement(PyStatementList.class).inside(psiElement(PyExceptPart.class)));
+ private static final PsiElementPattern.Capture<PsiElement> IN_ELSE_BODY_OF_TRY =
+ psiElement().inside(psiElement(PyStatementList.class).inside(psiElement(PyElsePart.class).inside(PyTryExceptStatement.class)));
+
private static final PsiElementPattern.Capture<PsiElement> AFTER_IF = afterStatement(psiElement(PyIfStatement.class).withLastChild(
psiElement(PyIfPart.class)));
private static final PsiElementPattern.Capture<PsiElement> AFTER_TRY = afterStatement(psiElement(PyTryExceptStatement.class));
@@ -379,8 +381,8 @@
protected void addCompletions(
@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result
) {
- putKeywords(result, TailType.NONE, PyKeywords.DEF, PyKeywords.CLASS, PyKeywords.FOR, PyKeywords.IF, PyKeywords.WHILE, PyKeywords.WITH);
- putKeywords(result, TailType.CASE_COLON, PyKeywords.TRY);
+ putKeywords(result, TailType.NONE, PyNames.DEF, PyNames.CLASS, PyNames.FOR, PyNames.IF, PyNames.WHILE, PyNames.WITH);
+ putKeywords(result, TailType.CASE_COLON, PyNames.TRY);
}
}
);
@@ -403,13 +405,13 @@
protected void addCompletions(
@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result
) {
- putKeywords(result, TailType.SPACE, PyKeywords.ASSERT, PyKeywords.DEL, PyKeywords.EXEC, PyKeywords.FROM, PyKeywords.IMPORT, PyKeywords.RAISE);
+ putKeywords(result, TailType.SPACE, PyNames.ASSERT, PyNames.DEL, PyNames.EXEC, PyNames.FROM, PyNames.IMPORT, PyNames.RAISE);
putKeywords(result, TailType.NONE, PyNames.PASS);
}
}
);
- extend(CompletionType.BASIC, inStatement.andNot(PY3K), new PyKeywordCompletionProvider(TailType.SPACE, PyKeywords.PRINT));
+ extend(CompletionType.BASIC, inStatement.andNot(PY3K), new PyKeywordCompletionProvider(TailType.SPACE, PyNames.PRINT));
}
private void addBreak() {
@@ -422,7 +424,7 @@
.andNot(IN_ARG_LIST)
.and(IN_LOOP)
,
- new PyKeywordCompletionProvider(TailType.NONE, PyKeywords.BREAK)
+ new PyKeywordCompletionProvider(TailType.NONE, PyNames.BREAK)
);
}
@@ -437,7 +439,7 @@
.andNot(IN_FINALLY_NO_LOOP)
.and(IN_LOOP)
,
- new PyKeywordCompletionProvider(TailType.NONE, PyKeywords.CONTINUE)
+ new PyKeywordCompletionProvider(TailType.NONE, PyNames.CONTINUE)
);
}
@@ -449,7 +451,7 @@
.and(IN_BEGIN_STMT)
.andNot(AFTER_QUALIFIER)
,
- new PyKeywordCompletionProvider(PyKeywords.GLOBAL, PyKeywords.RETURN, PyKeywords.YIELD)
+ new PyKeywordCompletionProvider(PyNames.GLOBAL, PyNames.RETURN, PyNames.YIELD)
);
extend(
@@ -460,7 +462,7 @@
.and(PY3K)
.andNot(AFTER_QUALIFIER)
,
- new PyKeywordCompletionProvider(PyKeywords.NONLOCAL)
+ new PyKeywordCompletionProvider(PyNames.NONLOCAL)
);
}
@@ -472,7 +474,7 @@
.andOr(IN_IF_BODY, AFTER_IF)
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
,
- new PyKeywordCompletionProvider(TailType.NONE, PyUnindentingInsertHandler.INSTANCE, PyKeywords.ELIF));
+ new PyKeywordCompletionProvider(TailType.NONE, PyUnindentingInsertHandler.INSTANCE, PyNames.ELIF));
}
private void addWithinTry() {
@@ -480,7 +482,7 @@
CompletionType.BASIC, psiElement()
.withLanguage(PythonLanguage.getInstance())
.and(FIRST_ON_LINE)
- .andOr(IN_TRY_BODY, IN_EXCEPT_BODY, AFTER_TRY)
+ .andOr(IN_TRY_BODY, IN_EXCEPT_BODY, AFTER_TRY, IN_ELSE_BODY_OF_TRY)
//.andNot(RIGHT_AFTER_COLON)
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
,
@@ -488,8 +490,8 @@
protected void addCompletions(
@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result
) {
- putKeyword(PyKeywords.EXCEPT, PyUnindentingInsertHandler.INSTANCE, TailType.NONE, result);
- putKeyword(PyKeywords.FINALLY, PyUnindentingInsertHandler.INSTANCE, TailType.CASE_COLON, result);
+ putKeyword(PyNames.EXCEPT, PyUnindentingInsertHandler.INSTANCE, TailType.NONE, result);
+ putKeyword(PyNames.FINALLY, PyUnindentingInsertHandler.INSTANCE, TailType.CASE_COLON, result);
}
}
);
@@ -503,7 +505,7 @@
.andOr(IN_COND_STMT, IN_EXCEPT_BODY, AFTER_COND_STMT_NO_ELSE, AFTER_LOOP_NO_ELSE, AFTER_EXCEPT)
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
,
- new PyKeywordCompletionProvider(TailType.CASE_COLON, PyUnindentingInsertHandler.INSTANCE, PyKeywords.ELSE));
+ new PyKeywordCompletionProvider(TailType.CASE_COLON, PyUnindentingInsertHandler.INSTANCE, PyNames.ELSE));
}
private void addInfixOperators() {
@@ -517,7 +519,7 @@
.andNot(AFTER_QUALIFIER).
andNot(IN_STRING_LITERAL).and(IN_BEGIN_STMT)
,
- new PyKeywordCompletionProvider(PyKeywords.AND, PyKeywords.OR, PyKeywords.IS, PyKeywords.IN)
+ new PyKeywordCompletionProvider(PyNames.AND, PyNames.OR, PyNames.IS, PyNames.IN)
);
}
@@ -531,7 +533,7 @@
.andNot(IN_FUNCTION_HEADER)
.andNot(AFTER_QUALIFIER).andNot(IN_STRING_LITERAL)
,
- new PyKeywordCompletionProvider(PyKeywords.NOT, PyKeywords.LAMBDA)
+ new PyKeywordCompletionProvider(PyNames.NOT, PyNames.LAMBDA)
);
}
@@ -546,7 +548,7 @@
.andNot(AFTER_QUALIFIER)
.andNot(IN_FUNCTION_HEADER)
,
- new PyKeywordCompletionProvider(TailType.NONE, PyKeywords.TRUE, PyKeywords.FALSE, PyKeywords.NONE)
+ new PyKeywordCompletionProvider(TailType.NONE, PyNames.TRUE, PyNames.FALSE, PyNames.NONE)
);
}
@@ -557,7 +559,7 @@
.andOr(IN_IMPORT_AFTER_REF, IN_WITH_AFTER_REF, IN_EXCEPT_AFTER_REF)
.andNot(AFTER_QUALIFIER)
,
- new PyKeywordCompletionProvider(PyKeywords.AS)
+ new PyKeywordCompletionProvider(PyNames.AS)
);
}
@@ -568,7 +570,7 @@
.and(IN_FROM_IMPORT_AFTER_REF)
.andNot(AFTER_QUALIFIER)
,
- new PyKeywordCompletionProvider(PyKeywords.IMPORT)
+ new PyKeywordCompletionProvider(PyNames.IMPORT)
);
}
@@ -604,9 +606,9 @@
.withLanguage(PythonLanguage.getInstance())
.afterLeafSkipping(psiElement().whitespace(),
psiElement().inside(psiElement(PyConditionalExpression.class))
- .and(psiElement().afterLeaf(PyKeywords.IF)))
+ .and(psiElement().afterLeaf(PyNames.IF)))
,
- new PyKeywordCompletionProvider(TailType.SPACE, PyKeywords.ELSE));
+ new PyKeywordCompletionProvider(TailType.SPACE, PyNames.ELSE));
}
private void addRaiseFrom() {
@@ -615,7 +617,7 @@
.withLanguage(PythonLanguage.getInstance())
.and(PY3K)
.afterLeaf(psiElement().inside(PyRaiseStatement.class)),
- new PyKeywordCompletionProvider(PyKeywords.FROM));
+ new PyKeywordCompletionProvider(PyNames.FROM));
}
private void addYieldFrom() {
@@ -624,7 +626,7 @@
.withLanguage(PythonLanguage.getInstance())
.and(PY3K)
.afterLeaf(psiElement().withElementType(PyTokenTypes.YIELD_KEYWORD)),
- new PyKeywordCompletionProvider(PyKeywords.FROM));
+ new PyKeywordCompletionProvider(PyNames.FROM));
}
public PyKeywordCompletionContributor() {
@@ -655,14 +657,14 @@
.withLanguage(PythonLanguage.getInstance())
.inside(psiElement(PySequenceExpression.class))
.andNot(psiElement().afterLeaf(or(psiElement(PyTokenTypes.LBRACE), psiElement(PyTokenTypes.LBRACKET), psiElement(PyTokenTypes.LPAR)))),
- new PyKeywordCompletionProvider(PyKeywords.FOR));
+ new PyKeywordCompletionProvider(PyNames.FOR));
}
private void addInToFor() {
extend(CompletionType.BASIC,
psiElement()
.withLanguage(PythonLanguage.getInstance())
- .and(psiElement()).afterLeaf(psiElement().afterLeaf(PyKeywords.FOR)),
+ .and(psiElement()).afterLeaf(psiElement().afterLeaf(PyNames.FOR)),
new PyKeywordCompletionProvider("in"));
}
diff --git a/python/src/com/jetbrains/python/codeInsight/dataflow/scope/Scope.java b/python/src/com/jetbrains/python/codeInsight/dataflow/scope/Scope.java
index 5cf0286..eedf3a6 100644
--- a/python/src/com/jetbrains/python/codeInsight/dataflow/scope/Scope.java
+++ b/python/src/com/jetbrains/python/codeInsight/dataflow/scope/Scope.java
@@ -19,6 +19,7 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.jetbrains.python.psi.PyImportedNameDefiner;
+import com.jetbrains.python.psi.PyTargetExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -49,4 +50,7 @@
@NotNull
Collection<PsiNamedElement> getNamedElements();
+
+ @NotNull
+ Collection<PyTargetExpression> getTargetExpressions();
}
diff --git a/python/src/com/jetbrains/python/codeInsight/dataflow/scope/impl/ScopeImpl.java b/python/src/com/jetbrains/python/codeInsight/dataflow/scope/impl/ScopeImpl.java
index d0eb376..19a947fe 100644
--- a/python/src/com/jetbrains/python/codeInsight/dataflow/scope/impl/ScopeImpl.java
+++ b/python/src/com/jetbrains/python/codeInsight/dataflow/scope/impl/ScopeImpl.java
@@ -47,6 +47,7 @@
private volatile Map<String, PsiNamedElement> myNamedElements;
private volatile List<PyImportedNameDefiner> myImportedNameDefiners; // Declarations which declare unknown set of imported names
private volatile Set<String> myAugAssignments;
+ private List<PyTargetExpression> myTargetExpressions;
public ScopeImpl(final ScopeOwner flowOwner) {
myFlowOwner = flowOwner;
@@ -170,6 +171,15 @@
return myNamedElements.values();
}
+ @NotNull
+ @Override
+ public Collection<PyTargetExpression> getTargetExpressions() {
+ if (myTargetExpressions == null) {
+ collectDeclarations();
+ }
+ return myTargetExpressions;
+ }
+
private void collectDeclarations() {
final Map<String, PsiNamedElement> namedElements = new HashMap<String, PsiNamedElement>();
final List<PyImportedNameDefiner> importedNameDefiners = new ArrayList<PyImportedNameDefiner>();
@@ -177,11 +187,13 @@
final Set<String> globals = new HashSet<String>();
final Set<String> nonlocals = new HashSet<String>();
final Set<String> augAssignments = new HashSet<String>();
+ final List<PyTargetExpression> targetExpressions = new ArrayList<PyTargetExpression>();
myFlowOwner.acceptChildren(new PyRecursiveElementVisitor() {
@Override
public void visitPyTargetExpression(PyTargetExpression node) {
+ targetExpressions.add(node);
final PsiElement parent = node.getParent();
- if (node.getQualifier() == null && !(parent instanceof PyImportElement)) {
+ if (!node.isQualified() && !(parent instanceof PyImportElement)) {
super.visitPyTargetExpression(node);
}
}
@@ -249,5 +261,6 @@
myGlobals = globals;
myNonlocals = nonlocals;
myAugAssignments = augAssignments;
+ myTargetExpressions = targetExpressions;
}
}
diff --git a/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java b/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java
index 4b46413..47c9ca9 100644
--- a/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java
+++ b/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java
@@ -129,7 +129,7 @@
if (HintManager.getInstance().hasShownHintsThatWillHideByOtherHint(true)) {
return false;
}
- if ((myNode instanceof PyQualifiedExpression) && ((((PyQualifiedExpression)myNode).getQualifier() != null))) return false; // we cannot be qualified
+ if ((myNode instanceof PyQualifiedExpression) && ((((PyQualifiedExpression)myNode).isQualified()))) return false; // we cannot be qualified
String name = getNameToImport();
if (!name.equals(myInitialName)) {
return false;
diff --git a/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java b/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java
index f90ce61..58254d9 100644
--- a/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java
+++ b/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java
@@ -82,7 +82,7 @@
// check if the tree is sane
PsiDocumentManager.getInstance(myTarget.getProject()).commitAllDocuments();
if (!myTarget.isValid()) return false;
- if ((myTarget instanceof PyQualifiedExpression) && ((((PyQualifiedExpression)myTarget).getQualifier() != null))) return false; // we cannot be qualified
+ if ((myTarget instanceof PyQualifiedExpression) && ((((PyQualifiedExpression)myTarget).isQualified()))) return false; // we cannot be qualified
for (ImportCandidateHolder item : mySources) {
if (!item.getImportable().isValid()) return false;
if (!item.getFile().isValid()) return false;
diff --git a/python/src/com/jetbrains/python/codeInsight/imports/PythonReferenceImporter.java b/python/src/com/jetbrains/python/codeInsight/imports/PythonReferenceImporter.java
index 06e4f89..ae96ac5 100644
--- a/python/src/com/jetbrains/python/codeInsight/imports/PythonReferenceImporter.java
+++ b/python/src/com/jetbrains/python/codeInsight/imports/PythonReferenceImporter.java
@@ -69,7 +69,7 @@
for (PsiElement element : elements) {
if (element instanceof PyReferenceExpression && isImportable(element)) {
final PyReferenceExpression refExpr = (PyReferenceExpression)element;
- if (refExpr.getQualifier() == null) {
+ if (!refExpr.isQualified()) {
final PsiPolyVariantReference reference = refExpr.getReference();
if (reference.resolve() == null) {
AutoImportQuickFix fix = proposeImportFix(refExpr, reference);
@@ -92,7 +92,7 @@
PsiReference element = file.findReferenceAt(offset);
if (element instanceof PyReferenceExpression && isImportable((PsiElement)element)) {
final PyReferenceExpression refExpr = (PyReferenceExpression)element;
- if (refExpr.getQualifier() == null) {
+ if (!refExpr.isQualified()) {
final PsiPolyVariantReference reference = refExpr.getReference();
if (reference.resolve() == null) {
AutoImportQuickFix fix = proposeImportFix(refExpr, reference);
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java
index 9f1c366..0170b8b 100644
--- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java
@@ -28,7 +28,7 @@
import com.intellij.util.containers.HashMap;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.*;
-import com.jetbrains.python.psi.resolve.PyResolveUtil;
+import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.jetbrains.python.psi.types.PyModuleType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.NotNull;
@@ -84,7 +84,7 @@
ret.myModuleReference = ret.myFromImportStatement.getImportSource();
}
if (ret.myModuleReference != null) {
- ret.myModuleName = PyResolveUtil.toPath(ret.myModuleReference);
+ ret.myModuleName = PyPsiUtils.toPath(ret.myModuleReference);
}
return ret;
}
@@ -117,7 +117,7 @@
if (info.myModuleReference != null) {
PyExpression remaining_module = info.myModuleReference.getQualifier();
if (remaining_module instanceof PyQualifiedExpression) {
- remaining_name = PyResolveUtil.toPath((PyQualifiedExpression)remaining_module);
+ remaining_name = PyPsiUtils.toPath((PyQualifiedExpression)remaining_module);
}
else remaining_name = ""; // unqualified name: "...module"
separated_name = info.myModuleReference.getReferencedName();
@@ -169,7 +169,7 @@
}
}
if (info.myModuleReference != null) {
- info.myModuleName = PyResolveUtil.toPath(info.myModuleReference);
+ info.myModuleName = PyPsiUtils.toPath(info.myModuleReference);
}
if (info.myModuleReference != null && info.myModuleName != null && info.myFromImportStatement != null) {
myText = info.getText();
@@ -211,7 +211,7 @@
public boolean execute(@NotNull PsiElement element) {
if (element instanceof PyReferenceExpression && PsiTreeUtil.getParentOfType(element, PyImportElement.class) == null && element.isValid()) {
PyReferenceExpression ref = (PyReferenceExpression)element;
- if (ref.getQualifier() == null) {
+ if (!ref.isQualified()) {
ResolveResult[] resolved = ref.getReference().multiResolve(false);
for (ResolveResult rr : resolved) {
if (rr.isValidResult()) {
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java
index 453c2895..fc35833 100644
--- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java
@@ -30,7 +30,7 @@
import com.intellij.util.containers.HashSet;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.*;
-import com.jetbrains.python.psi.resolve.PyResolveUtil;
+import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -94,7 +94,7 @@
// usages of imported name are qualifiers; what they refer to?
PyReferenceExpression reference = myImportElement.getImportReferenceExpression();
if (reference != null) {
- myModuleName = PyResolveUtil.toPath(reference);
+ myModuleName = PyPsiUtils.toPath(reference);
myQualifierName = myImportElement.getVisibleName();
myReferee = reference.getReference().resolve();
myHasModuleReference = false;
@@ -104,7 +104,7 @@
public boolean execute(@NotNull PsiElement element) {
if (element instanceof PyReferenceExpression && PsiTreeUtil.getParentOfType(element, PyImportElement.class) == null) {
PyReferenceExpression ref = (PyReferenceExpression)element;
- if (myQualifierName.equals(PyResolveUtil.toPath(ref))) { // filter out other names that might resolve to our target
+ if (myQualifierName.equals(PyPsiUtils.toPath(ref))) { // filter out other names that might resolve to our target
PsiElement parent_elt = ref.getParent();
if (parent_elt instanceof PyQualifiedExpression) { // really qualified by us, not just referencing?
PsiElement resolved = ref.getReference().resolve();
@@ -197,7 +197,7 @@
String module_name = "?";
if (myImportElement != null) {
PyReferenceExpression reference = myImportElement.getImportReferenceExpression();
- if (reference != null) module_name = PyResolveUtil.toPath(reference);
+ if (reference != null) module_name = PyPsiUtils.toPath(reference);
}
return PyBundle.message("INTN.convert.to.from.$0.import.$1", getDots()+module_name, "...");
}
diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java
index 6b79d21..621adf8 100644
--- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java
+++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java
@@ -38,7 +38,7 @@
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.psi.*;
-import com.jetbrains.python.psi.resolve.PyResolveUtil;
+import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -136,7 +136,7 @@
PyReferenceExpression reference = sure(state.myImportElement.getImportReferenceExpression());
// search for references to us with the right name
try {
- String imported_name = PyResolveUtil.toPath(reference);
+ String imported_name = PyPsiUtils.toPath(reference);
if (state.myAlias != null) {
// have to remove alias, rename everything to original
target_name = imported_name;
@@ -201,7 +201,7 @@
if (element instanceof PyReferenceExpression && PsiTreeUtil.getParentOfType(element,
PyImportElement.class) == null) {
PyReferenceExpression ref = (PyReferenceExpression)element;
- if (remove_name.equals(PyResolveUtil.toPath(ref))) { // filter out other names that might resolve to our target
+ if (remove_name.equals(PyPsiUtils.toPath(ref))) { // filter out other names that might resolve to our target
PsiElement resolved = ref.getReference().resolve();
if (resolved == referee) references.add(ref.getReference());
}
diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java
index e49b0bd..8783a7a 100644
--- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java
+++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java
@@ -156,7 +156,8 @@
final int offset = editor.getCaretModel().getOffset();
PsiElement anchor = null;
for (PyStatement statement: statementList.getStatements()) {
- if (statement.getTextRange().getStartOffset() < offset) {
+ if (statement.getTextRange().getStartOffset() < offset ||
+ (statement instanceof PyExpressionStatement && ((PyExpressionStatement)statement).getExpression() instanceof PyStringLiteralExpression)) {
anchor = statement;
}
}
diff --git a/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpInjector.java b/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpInjector.java
index bb23c47..029eabc 100644
--- a/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpInjector.java
+++ b/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpInjector.java
@@ -18,12 +18,17 @@
import com.intellij.lang.Language;
import com.intellij.lang.injection.MultiHostInjector;
import com.intellij.lang.injection.MultiHostRegistrar;
+import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiPolyVariantReference;
+import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
+import com.intellij.psi.impl.source.tree.injected.MultiHostRegistrarImpl;
+import com.intellij.psi.impl.source.tree.injected.Place;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.jetbrains.python.codeInsight.PyInjectionUtil;
-import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import org.jetbrains.annotations.NotNull;
@@ -77,12 +82,20 @@
final PsiPolyVariantReference ref = ((PyReferenceExpression)callee).getReference(PyResolveContext.noImplicits());
if (ref != null) {
final PsiElement element = ref.resolve();
- if (element != null && PsiTreeUtil.getParentOfType(element, ScopeOwner.class) instanceof PyFile &&
+ if (element != null && ScopeUtil.getScopeOwner(element) instanceof PyFile &&
element.getContainingFile().getName().equals("re.py") && isRegexpMethod(element, index)) {
final Language language = isVerbose(call) ? PythonVerboseRegexpLanguage.INSTANCE : PythonRegexpLanguage.INSTANCE;
registrar.startInjecting(language);
- PyInjectionUtil.registerStringLiteralInjection(context, registrar);
- registrar.doneInjecting();
+ final PyInjectionUtil.InjectionResult result = PyInjectionUtil.registerStringLiteralInjection(context, registrar);
+ if (result.isInjected()) {
+ registrar.doneInjecting();
+ if (!result.isStrict()) {
+ final PsiFile file = getInjectedFile(registrar);
+ if (file != null) {
+ file.putUserData(InjectedLanguageUtil.FRANKENSTEIN_INJECTION, Boolean.TRUE);
+ }
+ }
+ }
}
}
}
@@ -90,6 +103,13 @@
}
}
+ @Nullable
+ private static PsiFile getInjectedFile(@NotNull MultiHostRegistrar registrar) {
+ // Don't add a dependency on IntelliLang here now, but this injector should become IntelliLang-based in the future
+ final List<Pair<Place,PsiFile>> result = ((MultiHostRegistrarImpl)registrar).getResult();
+ return result == null || result.isEmpty() ? null : result.get(result.size() - 1).second;
+ }
+
@NotNull
@Override
public List<? extends Class<? extends PsiElement>> elementsToInjectIn() {
diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java
index 9e2989e..9cdf4c3 100644
--- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java
+++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java
@@ -21,6 +21,8 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.PyNames;
+import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyTypeProvider;
@@ -30,6 +32,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -54,28 +57,62 @@
@Override
public PyType getReferenceType(@NotNull PsiElement referenceTarget, @NotNull TypeEvalContext context, @Nullable PsiElement anchor) {
+ PyType type = getNamedTupleType(referenceTarget, anchor);
+ if (type != null) {
+ return type;
+ }
+ type = getEnumType(referenceTarget, context, anchor);
+ if (type != null) {
+ return type;
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PyType getEnumType(@NotNull PsiElement referenceTarget, @NotNull TypeEvalContext context,
+ @Nullable PsiElement anchor) {
if (referenceTarget instanceof PyTargetExpression) {
final PyTargetExpression target = (PyTargetExpression)referenceTarget;
- final QualifiedName calleeName = target.getCalleeName();
- if (calleeName != null && PyNames.NAMEDTUPLE.equals(calleeName.toString())) {
- // TODO: Create stubs for namedtuple for preventing switch from stub to AST
- final PyExpression value = target.findAssignedValue();
- if (value instanceof PyCallExpression) {
- final PyCallExpression call = (PyCallExpression)value;
- final PyCallExpression.PyMarkedCallee callee = call.resolveCallee(PyResolveContext.noImplicits());
- if (callee != null) {
- final Callable callable = callee.getCallable();
- if (PyNames.COLLECTIONS_NAMEDTUPLE.equals(callable.getQualifiedName())) {
- return PyNamedTupleType.fromCall(call, 1);
+ final ScopeOwner owner = ScopeUtil.getScopeOwner(target);
+ if (owner instanceof PyClass) {
+ final PyClass cls = (PyClass)owner;
+ final List<PyClassLikeType> types = cls.getAncestorTypes(context);
+ for (PyClassLikeType type : types) {
+ if (type != null && "enum.Enum".equals(type.getClassQName())) {
+ final PyType classType = context.getType(cls);
+ if (classType instanceof PyClassType) {
+ return ((PyClassType)classType).toInstance();
}
}
}
}
}
- else if (referenceTarget instanceof PyFunction && anchor instanceof PyCallExpression) {
- final PyFunction function = (PyFunction)referenceTarget;
- if (PyNames.NAMEDTUPLE.equals(function.getName()) && PyNames.COLLECTIONS_NAMEDTUPLE.equals(function.getQualifiedName())) {
- return PyNamedTupleType.fromCall((PyCallExpression)anchor, 2);
+ if (referenceTarget instanceof PyQualifiedNameOwner) {
+ final PyQualifiedNameOwner qualifiedNameOwner = (PyQualifiedNameOwner)referenceTarget;
+ final String name = qualifiedNameOwner.getQualifiedName();
+ if ("enum.Enum.name".equals(name)) {
+ return PyBuiltinCache.getInstance(referenceTarget).getStrType();
+ }
+ else if ("enum.Enum.value".equals(name) && anchor instanceof PyReferenceExpression && context.maySwitchToAST(anchor)) {
+ final PyReferenceExpression anchorExpr = (PyReferenceExpression)anchor;
+ final PyExpression qualifier = anchorExpr.getQualifier();
+ if (qualifier instanceof PyReferenceExpression) {
+ final PyReferenceExpression qualifierExpr = (PyReferenceExpression)qualifier;
+ final PsiElement resolvedQualifier = qualifierExpr.getReference().resolve();
+ if (resolvedQualifier instanceof PyTargetExpression) {
+ final PyTargetExpression qualifierTarget = (PyTargetExpression)resolvedQualifier;
+ // Requires switching to AST, we cannot use getType(qualifierTarget) here, because its type is overridden by this type provider
+ if (context.maySwitchToAST(qualifierTarget)) {
+ final PyExpression value = qualifierTarget.findAssignedValue();
+ if (value != null) {
+ return context.getType(value);
+ }
+ }
+ }
+ }
+ }
+ else if ("enum.EnumMeta.__members__".equals(name)) {
+ return PyTypeParser.getTypeByName(referenceTarget, "dict[str, unknown]");
}
}
return null;
@@ -101,18 +138,6 @@
@Nullable
@Override
- public PyType getIterationType(@NotNull PyClass iterable) {
- final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(iterable);
- if (builtinCache.hasInBuiltins(iterable)) {
- if ("file".equals(iterable.getName())) {
- return builtinCache.getStrType();
- }
- }
- return null;
- }
-
- @Nullable
- @Override
public PyType getContextManagerVariableType(@NotNull PyClass contextManager, @NotNull PyExpression withExpression, @NotNull TypeEvalContext context) {
if ("contextlib.closing".equals(contextManager.getQualifiedName()) && withExpression instanceof PyCallExpression) {
PyExpression closee = ((PyCallExpression)withExpression).getArgument(0, PyExpression.class);
@@ -128,6 +153,35 @@
}
@Nullable
+ private static PyType getNamedTupleType(@NotNull PsiElement referenceTarget, @Nullable PsiElement anchor) {
+ if (referenceTarget instanceof PyTargetExpression) {
+ final PyTargetExpression target = (PyTargetExpression)referenceTarget;
+ final QualifiedName calleeName = target.getCalleeName();
+ if (calleeName != null && PyNames.NAMEDTUPLE.equals(calleeName.toString())) {
+ // TODO: Create stubs for namedtuple for preventing switch from stub to AST
+ final PyExpression value = target.findAssignedValue();
+ if (value instanceof PyCallExpression) {
+ final PyCallExpression call = (PyCallExpression)value;
+ final PyCallExpression.PyMarkedCallee callee = call.resolveCallee(PyResolveContext.noImplicits());
+ if (callee != null) {
+ final Callable callable = callee.getCallable();
+ if (PyNames.COLLECTIONS_NAMEDTUPLE.equals(callable.getQualifiedName())) {
+ return PyNamedTupleType.fromCall(call, 1);
+ }
+ }
+ }
+ }
+ }
+ else if (referenceTarget instanceof PyFunction && anchor instanceof PyCallExpression) {
+ final PyFunction function = (PyFunction)referenceTarget;
+ if (PyNames.NAMEDTUPLE.equals(function.getName()) && PyNames.COLLECTIONS_NAMEDTUPLE.equals(function.getQualifiedName())) {
+ return PyNamedTupleType.fromCall((PyCallExpression)anchor, 2);
+ }
+ }
+ return null;
+ }
+
+ @Nullable
private static PyType getOpenFunctionType(@NotNull String callQName,
@NotNull Map<PyExpression, PyNamedParameter> arguments,
@NotNull PsiElement anchor) {
diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java
index 2d0fd8d..5ee041c 100644
--- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java
+++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java
@@ -23,6 +23,7 @@
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;
@@ -55,6 +56,7 @@
public class PyUserSkeletonsUtil {
public static final String USER_SKELETONS_DIR = "python-skeletons";
private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil");
+ public static final Key<Boolean> HAS_SKELETON = Key.create("PyUserSkeleton.hasSkeleton");
@Nullable private static VirtualFile ourUserSkeletonsDirectory;
private static boolean ourNoSkeletonsErrorReported = false;
@@ -177,6 +179,10 @@
@Nullable
private static PyFile getUserSkeletonForFile(@NotNull PyFile file) {
+ final Boolean hasSkeleton = file.getUserData(HAS_SKELETON);
+ if (hasSkeleton != null && !hasSkeleton) {
+ return null;
+ }
final VirtualFile moduleVirtualFile = file.getVirtualFile();
if (moduleVirtualFile != null) {
String moduleName = QualifiedNameFinder.findShortestImportableName(file, moduleVirtualFile);
@@ -188,7 +194,9 @@
moduleName = restored.toString();
}
}
- return getUserSkeletonForModuleQName(moduleName, file);
+ final PyFile skeletonFile = getUserSkeletonForModuleQName(moduleName, file);
+ file.putUserData(HAS_SKELETON, skeletonFile != null);
+ return skeletonFile;
}
}
return null;
diff --git a/python/src/com/jetbrains/python/console/PyConsoleProcessHandler.java b/python/src/com/jetbrains/python/console/PyConsoleProcessHandler.java
index 4ea06d6..c0c65fc 100644
--- a/python/src/com/jetbrains/python/console/PyConsoleProcessHandler.java
+++ b/python/src/com/jetbrains/python/console/PyConsoleProcessHandler.java
@@ -24,7 +24,7 @@
import java.nio.charset.Charset;
/**
- * @author oleg
+ * @author traff
*/
public class PyConsoleProcessHandler extends PythonProcessHandler {
private final PythonConsoleView myConsoleView;
@@ -57,6 +57,11 @@
return !myPydevConsoleCommunication.isExecuting();
}
+ @Override
+ protected boolean shouldKillProcessSoftly() {
+ return false;
+ }
+
private void doCloseCommunication() {
if (myPydevConsoleCommunication != null) {
diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
index 759bf71..1c1b814 100644
--- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
+++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
@@ -77,6 +77,7 @@
private final List<PyThreadInfo> mySuspendedThreads = Collections.synchronizedList(Lists.<PyThreadInfo>newArrayList());
private final Map<String, XValueChildrenList> myStackFrameCache = Maps.newHashMap();
private final Map<String, PyDebugValue> myNewVariableValue = Maps.newHashMap();
+ private boolean myDownloadSources = false;
private boolean myClosing = false;
@@ -422,8 +423,17 @@
cleanUp();
}
+ public boolean isDownloadSources() {
+ return myDownloadSources;
+ }
+
+ public void setDownloadSources(boolean downloadSources) {
+ myDownloadSources = downloadSources;
+ }
+
protected void cleanUp() {
mySuspendedThreads.clear();
+ myDownloadSources = false;
}
@Override
diff --git a/python/src/com/jetbrains/python/documentation/DocStringParameterReference.java b/python/src/com/jetbrains/python/documentation/DocStringParameterReference.java
index 5f7a2ee..968d413 100644
--- a/python/src/com/jetbrains/python/documentation/DocStringParameterReference.java
+++ b/python/src/com/jetbrains/python/documentation/DocStringParameterReference.java
@@ -17,14 +17,17 @@
import com.google.common.collect.Lists;
import com.intellij.lang.annotation.HighlightSeverity;
+import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiReferenceBase;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
+import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashSet;
import com.jetbrains.python.PyNames;
+import com.jetbrains.python.PythonStringUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.ParamHelper;
import com.jetbrains.python.psi.types.TypeEvalContext;
@@ -37,10 +40,10 @@
/**
* @author yole
*/
-public class DocStringParameterReference extends PsiReferenceBase<PsiElement> implements PsiReferenceEx {
+public class DocStringParameterReference extends PsiReferenceBase<PyStringLiteralExpression> implements PsiReferenceEx {
private final StructuredDocStringBase.ReferenceType myType;
- public DocStringParameterReference(PsiElement element, TextRange range, StructuredDocStringBase.ReferenceType refType) {
+ public DocStringParameterReference(PyStringLiteralExpression element, TextRange range, StructuredDocStringBase.ReferenceType refType) {
super(element, range);
myType = refType;
}
@@ -159,4 +162,18 @@
}
return null;
}
+
+ @Override
+ public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ TextRange range = getRangeInElement();
+ Pair<String, String> quotes = PythonStringUtil.getQuotes(range.substring(myElement.getText()));
+
+ if (quotes != null) {
+ range = TextRange.create(range.getStartOffset() + quotes.first.length(), range.getEndOffset() - quotes.second.length());
+ }
+
+ String newName = range.replace(myElement.getText(), newElementName);
+ myElement.updateText(newName);
+ return myElement;
+ }
}
diff --git a/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java b/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java
index d1d8033..9eea80c 100644
--- a/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java
+++ b/python/src/com/jetbrains/python/documentation/DocStringReferenceProvider.java
@@ -59,22 +59,22 @@
// XXX: It does not work with multielement docstrings
StructuredDocString docString = DocStringUtil.parse(text);
if (docString != null) {
- result.addAll(referencesFromNames(element, offset, docString,
+ result.addAll(referencesFromNames(expr, offset, docString,
docString.getTagArguments(StructuredDocStringBase.PARAM_TAGS),
StructuredDocStringBase.ReferenceType.PARAMETER));
- result.addAll(referencesFromNames(element, offset, docString,
+ result.addAll(referencesFromNames(expr, offset, docString,
docString.getTagArguments(StructuredDocStringBase.PARAM_TYPE_TAGS),
StructuredDocStringBase.ReferenceType.PARAMETER_TYPE));
- result.addAll(referencesFromNames(element, offset, docString,
+ result.addAll(referencesFromNames(expr, offset, docString,
docString.getKeywordArgumentSubstrings(), StructuredDocStringBase.ReferenceType.KEYWORD));
- result.addAll(referencesFromNames(element, offset, docString,
+ result.addAll(referencesFromNames(expr, offset, docString,
docString.getTagArguments("var"),
StructuredDocStringBase.ReferenceType.VARIABLE));
- result.addAll(referencesFromNames(element, offset, docString,
+ result.addAll(referencesFromNames(expr, offset, docString,
docString.getTagArguments("cvar"),
StructuredDocStringBase.ReferenceType.CLASS_VARIABLE));
- result.addAll(referencesFromNames(element, offset, docString,
+ result.addAll(referencesFromNames(expr, offset, docString,
docString.getTagArguments("ivar"),
StructuredDocStringBase.ReferenceType.INSTANCE_VARIABLE));
result.addAll(returnTypes(element, docString, offset));
@@ -96,7 +96,7 @@
}
return result;
}
- private static List<PsiReference> referencesFromNames(PsiElement element,
+ private static List<PsiReference> referencesFromNames(PyStringLiteralExpression element,
int offset,
StructuredDocString docString,
List<Substring> paramNames,
diff --git a/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java b/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java
index d7358f1..d09af58 100644
--- a/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java
+++ b/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java
@@ -222,8 +222,9 @@
}
replacementText.append(line);
}
- if (replacementText.length() > 0)
- replacementText.deleteCharAt(replacementText.length()-1);
+ if (replacementText.length() > 0) {
+ replacementText.deleteCharAt(replacementText.length() - 1);
+ }
addParams(replacementText, false, paramsToAdd);
for (int i = ind; i != lines.length; ++i) {
String line = lines[i];
@@ -250,7 +251,7 @@
final Module module = ModuleUtilCore.findModuleForPsiElement(myDocStringOwner);
if (module != null) {
PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(module);
- if (documentationSettings.isPlain(getFile())) return replacementText.length()-1;
+ if (documentationSettings.isPlain(getFile())) return replacementText.length() - 1;
}
int i = 0;
@@ -418,7 +419,8 @@
"def " + myFunction.getName() + myFunction.getParameterList().getText()
+ ":\n" + StringUtil.repeat(" ", getIndentSize(myFunction))
+ replacement + "\n" +
- StringUtil.repeat(" ", getIndentSize(myFunction)) + list.getText());
+ StringUtil.repeat(" ", getIndentSize(myFunction)) + list.getText()
+ );
myFunction = (PyFunction)myFunction.replace(func);
}
@@ -429,7 +431,9 @@
}
myFunction = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(myFunction);
- myDocStringExpression = myFunction.getDocStringExpression();
+ if (myFunction != null) {
+ myDocStringExpression = myFunction.getDocStringExpression();
+ }
}
}
diff --git a/python/src/com/jetbrains/python/documentation/doctest/PyDocReferenceExpression.java b/python/src/com/jetbrains/python/documentation/doctest/PyDocReferenceExpression.java
index 1199583..62356d2 100644
--- a/python/src/com/jetbrains/python/documentation/doctest/PyDocReferenceExpression.java
+++ b/python/src/com/jetbrains/python/documentation/doctest/PyDocReferenceExpression.java
@@ -19,7 +19,6 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.util.PsiTreeUtil;
-import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyFromImportStatement;
import com.jetbrains.python.psi.PyImportElement;
import com.jetbrains.python.psi.impl.PyReferenceExpressionImpl;
@@ -40,8 +39,7 @@
@NotNull
public PsiPolyVariantReference getReference(PyResolveContext context) {
- final PyExpression qualifier = getQualifier();
- if (qualifier != null) {
+ if (isQualified()) {
return new PyQualifiedReference(this, context);
}
final PsiElement importParent = PsiTreeUtil.getParentOfType(this, PyImportElement.class, PyFromImportStatement.class);
diff --git a/python/src/com/jetbrains/python/editor/selectWord/PyListSelectionHandler.java b/python/src/com/jetbrains/python/editor/selectWord/PyListSelectionHandler.java
index a45c8c2..b394203 100644
--- a/python/src/com/jetbrains/python/editor/selectWord/PyListSelectionHandler.java
+++ b/python/src/com/jetbrains/python/editor/selectWord/PyListSelectionHandler.java
@@ -19,6 +19,7 @@
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiWhiteSpace;
import com.jetbrains.python.psi.PyArgumentList;
import com.jetbrains.python.psi.PyListLiteralExpression;
@@ -42,6 +43,9 @@
public List<TextRange> select(PsiElement e, CharSequence editorText, int cursorOffset, Editor editor) {
TextRange stringRange = e.getTextRange();
PsiElement firstChild = e.getFirstChild().getNextSibling();
+ if (firstChild instanceof PsiErrorElement) {
+ return Collections.emptyList();
+ }
int startShift = 1;
if (firstChild instanceof PsiWhiteSpace)
startShift += firstChild.getTextLength();
@@ -50,7 +54,7 @@
if (lastChild instanceof PsiWhiteSpace)
endShift += lastChild.getTextLength();
- TextRange offsetRange = new TextRange(stringRange.getStartOffset() + startShift, stringRange.getEndOffset() - endShift );
+ final TextRange offsetRange = new TextRange(stringRange.getStartOffset() + startShift, stringRange.getEndOffset() - endShift);
if (offsetRange.contains(cursorOffset) && offsetRange.getLength() > 1) {
return Collections.singletonList(offsetRange);
}
diff --git a/python/src/com/jetbrains/python/formatter/PyBlock.java b/python/src/com/jetbrains/python/formatter/PyBlock.java
index 8afd35e..d160749 100644
--- a/python/src/com/jetbrains/python/formatter/PyBlock.java
+++ b/python/src/com/jetbrains/python/formatter/PyBlock.java
@@ -161,6 +161,9 @@
if (needListAlignment(child) && !isEmptyList(_node.getPsi())) {
childAlignment = getAlignmentForChildren();
}
+ if (childType == PyTokenTypes.END_OF_LINE_COMMENT) {
+ childIndent = Indent.getNormalIndent();
+ }
}
else if (parentType == PyElementTypes.BINARY_EXPRESSION &&
(PythonDialectsTokenSetProvider.INSTANCE.getExpressionTokens().contains(childType) ||
@@ -188,16 +191,6 @@
childIndent = Indent.getNormalIndent();
}
}
- else if (parentType == PyElementTypes.ARGUMENT_LIST || parentType == PyElementTypes.PARAMETER_LIST) {
- if (childType == PyTokenTypes.RPAR) {
- childIndent = Indent.getNoneIndent();
- }
- else {
- childIndent = parentType == PyElementTypes.PARAMETER_LIST || isInControlStatement()
- ? Indent.getContinuationIndent()
- : Indent.getNormalIndent(/*true*/);
- }
- }
else if (parentType == PyElementTypes.DICT_LITERAL_EXPRESSION || parentType == PyElementTypes.SET_LITERAL_EXPRESSION ||
parentType == PyElementTypes.SET_COMP_EXPRESSION || parentType == PyElementTypes.DICT_COMP_EXPRESSION) {
if (childType == PyTokenTypes.RBRACE || !hasLineBreaksBefore(child, 1)) {
@@ -233,12 +226,40 @@
childIndent = Indent.getNormalIndent();
}
}
- else if (parentType == PyElementTypes.PARENTHESIZED_EXPRESSION || parentType == PyElementTypes.GENERATOR_EXPRESSION) {
+ //Align elements vertically if there is an argument in the first line of parenthesized expression
+ else if (((parentType == PyElementTypes.PARENTHESIZED_EXPRESSION && myContext.getSettings().ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION)
+ || (parentType == PyElementTypes.ARGUMENT_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS)
+ || (parentType == PyElementTypes.PARAMETER_LIST && myContext.getSettings().ALIGN_MULTILINE_PARAMETERS)) &&
+ !isIndentNext(child) &&
+ !hasLineBreaksBefore(_node.getFirstChildNode(), 1)
+ && !ourListElementTypes.contains(childType)) {
+
+ if (!ourBrackets.contains(childType)) {
+ childAlignment = getAlignmentForChildren();
+ if (parentType != PyElementTypes.CALL_EXPRESSION) {
+ childIndent = Indent.getNormalIndent();
+ }
+ }
+ else if (childType == PyTokenTypes.RPAR) {
+ childIndent = Indent.getNoneIndent();
+ }
+ }
+ else if (parentType == PyElementTypes.GENERATOR_EXPRESSION || parentType == PyElementTypes.PARENTHESIZED_EXPRESSION) {
if (childType == PyTokenTypes.RPAR || !hasLineBreaksBefore(child, 1)) {
childIndent = Indent.getNoneIndent();
}
else {
- childIndent = Indent.getNormalIndent();
+ childIndent = isIndentNext(child) ? Indent.getContinuationIndent() : Indent.getNormalIndent();
+ }
+ }
+ else if (parentType == PyElementTypes.ARGUMENT_LIST || parentType == PyElementTypes.PARAMETER_LIST) {
+ if (childType == PyTokenTypes.RPAR) {
+ childIndent = Indent.getNoneIndent();
+ }
+ else {
+ childIndent = parentType == PyElementTypes.PARAMETER_LIST || isInControlStatement()
+ ? Indent.getContinuationIndent()
+ : Indent.getNormalIndent(/*true*/);
}
}
else if (parentType == PyElementTypes.SUBSCRIPTION_EXPRESSION) {
@@ -250,6 +271,23 @@
else if (parentType == PyElementTypes.REFERENCE_EXPRESSION) {
if (child != _node.getFirstChildNode()) {
childIndent = Indent.getNormalIndent();
+ if (hasLineBreaksBefore(child, 1)) {
+ if (isInControlStatement()) {
+ childIndent = Indent.getContinuationIndent();
+ }
+ else {
+ PyBlock b = myParent;
+ while (b != null) {
+ if (b.getNode().getPsi() instanceof PyParenthesizedExpression ||
+ b.getNode().getPsi() instanceof PyArgumentList ||
+ b.getNode().getPsi() instanceof PyParameterList) {
+ childAlignment = getAlignmentOfChild(b, 1);
+ break;
+ }
+ b = b.myParent;
+ }
+ }
+ }
}
}
@@ -271,6 +309,14 @@
return new PyBlock(this, child, childAlignment, childIndent, wrap, myContext);
}
+ private static Alignment getAlignmentOfChild(PyBlock b, int childNum) {
+ if (b.getSubBlocks().size() > childNum) {
+ ChildAttributes attributes = b.getChildAttributes(childNum);
+ return attributes.getAlignment();
+ }
+ return null;
+ }
+
private static boolean isIndentNext(ASTNode child) {
PsiElement psi = PsiTreeUtil.getParentOfType(child.getPsi(), PyStatement.class);
@@ -281,7 +327,8 @@
psi instanceof PyFunction ||
psi instanceof PyTryExceptStatement ||
psi instanceof PyElsePart ||
- psi instanceof PyIfPart;
+ psi instanceof PyIfPart ||
+ psi instanceof PyWhileStatement;
}
private static boolean isSubscriptionOperand(ASTNode child) {
@@ -468,6 +515,10 @@
}
}
}
+
+ if (psi2 instanceof PsiComment && !hasLineBreaksBefore(psi2.getNode(), 1)) {
+ return Spacing.createSpacing(2, 0, 0, false, 0);
+ }
}
return myContext.getSpacingBuilder().getSpacing(this, child1, child2);
}
diff --git a/python/src/com/jetbrains/python/formatter/PyWhiteSpaceFormattingStrategy.java b/python/src/com/jetbrains/python/formatter/PyWhiteSpaceFormattingStrategy.java
index 77f9920..6a09e9c7 100644
--- a/python/src/com/jetbrains/python/formatter/PyWhiteSpaceFormattingStrategy.java
+++ b/python/src/com/jetbrains/python/formatter/PyWhiteSpaceFormattingStrategy.java
@@ -134,6 +134,9 @@
static TIntIntHashMap countBackSlashes(CharSequence text, int start, int end) {
TIntIntHashMap result = new TIntIntHashMap();
int line = 0;
+ if (end > text.length()) {
+ end = text.length();
+ }
for (int i = start; i < end; i++) {
char c = text.charAt(i);
switch (c) {
diff --git a/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java b/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java
index 82013d3..6a06f87 100644
--- a/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyArgumentEqualDefaultInspection.java
@@ -131,6 +131,10 @@
if (key.getText().equals(defaultValue.getText()))
return true;
}
+ if (key instanceof PyBinaryExpression && defaultValue instanceof PyBinaryExpression) {
+ if (key.getText().equals(defaultValue.getText()))
+ return true;
+ }
else if (key instanceof PyStringLiteralExpression && defaultValue instanceof PyStringLiteralExpression) {
if (((PyStringLiteralExpression)key).getStringValue().equals(((PyStringLiteralExpression)defaultValue).getStringValue()))
return true;
diff --git a/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java b/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java
index 6faea31..9a87959 100644
--- a/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java
@@ -173,12 +173,12 @@
PyType inside_type = context.getType(content);
if (inside_type != null && !PyTypeChecker.isUnknown(inside_type)) {
if (((PyStarArgument)arg).isKeyword()) {
- if (!PyABCUtil.isSubtype(inside_type, PyNames.MAPPING)) {
+ if (!PyABCUtil.isSubtype(inside_type, PyNames.MAPPING, context)) {
holder.registerProblem(arg, PyBundle.message("INSP.expected.dict.got.$0", inside_type.getName()));
}
}
else { // * arg
- if (!PyABCUtil.isSubtype(inside_type, PyNames.ITERABLE)) {
+ if (!PyABCUtil.isSubtype(inside_type, PyNames.ITERABLE, context)) {
holder.registerProblem(arg, PyBundle.message("INSP.expected.iter.got.$0", inside_type.getName()));
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspection.java b/python/src/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspection.java
new file mode 100644
index 0000000..aefbc34
--- /dev/null
+++ b/python/src/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspection.java
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.inspections;
+
+import com.intellij.codeInspection.LocalInspectionToolSession;
+import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.openapi.util.Condition;
+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.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+//TODO: Try to share logic with AssignmentToForLoopParameterInspection
+
+/**
+ * Checks for cases when you rewrite loop variable with inner loop.
+ * It finds all <code>with</code> and <code>for</code> statements, takes variables declared by them and ensures none of parent
+ * <code>with</code> or <code>for</code> declares variable with the same name
+ *
+ * @author link
+ */
+public class PyAssignmentToLoopOrWithParameterInspection extends PyInspection {
+
+ private static final String NAME = PyBundle.message("INSP.NAME.assignment.to.loop.or.with.parameter.display.name");
+
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return NAME;
+ }
+
+
+ @NotNull
+ @Override
+ public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder,
+ boolean isOnTheFly,
+ @NotNull final LocalInspectionToolSession session) {
+ return new Visitor(holder, session);
+ }
+
+ private static class Visitor extends PyInspectionVisitor {
+ private Visitor(@Nullable ProblemsHolder holder, @NotNull LocalInspectionToolSession session) {
+ super(holder, session);
+ }
+
+ @Override
+ public void visitPyWithStatement(PyWithStatement node) {
+ checkNotReDeclaringUpperLoopOrStatement(node);
+ }
+
+ @Override
+ public void visitPyForStatement(PyForStatement node) {
+ checkNotReDeclaringUpperLoopOrStatement(node);
+ }
+
+ /**
+ * Finds first parent of specific type (See {@link #isRequiredStatement(com.intellij.psi.PsiElement)})
+ * that declares one of names, declared in this statement
+ */
+ private void checkNotReDeclaringUpperLoopOrStatement(NameDefiner statement) {
+ for (PsiElement declaredVar : statement.iterateNames()) {
+ Filter filter = new Filter(handleSubscriptionsAndResolveSafely(declaredVar));
+ PsiElement firstParent = PsiTreeUtil.findFirstParent(statement, true, filter);
+ if (firstParent != null && isRequiredStatement(firstParent)) {
+ registerProblem(declaredVar,
+ PyBundle.message("INSP.NAME.assignment.to.loop.or.with.parameter.display.message", declaredVar.getText()));
+ }
+ }
+ }
+ }
+
+ /**
+ * Filters list of parents trying to find parent that declares var that refers to {@link #node}
+ * Returns {@link com.jetbrains.python.codeInsight.controlflow.ScopeOwner} if nothing found.
+ * Returns parent otherwise.
+ */
+ private static class Filter implements Condition<PsiElement> {
+ private final PsiElement node;
+
+ private Filter(PsiElement node) {
+ this.node = node;
+ }
+
+ @Override
+ public boolean value(PsiElement psiElement) {
+ if (psiElement instanceof ScopeOwner) {
+ return true; //Do not go any further
+ }
+ if (!(isRequiredStatement(psiElement))) {
+ return false; //Parent has wrong type, skip
+ }
+ Iterable<PyElement> varsDeclaredInStatement = ((NameDefiner)psiElement).iterateNames();
+ for (PsiElement varDeclaredInStatement : varsDeclaredInStatement) {
+ //For each variable, declared by this parent take first declaration and open subscription list if any
+ PsiReference reference = handleSubscriptionsAndResolveSafely(varDeclaredInStatement).getReference();
+ if (reference != null && reference.isReferenceTo(node)) {
+ return true; //One of variables declared by this parent refers to node
+ }
+ }
+ return false;
+ }
+
+ }
+
+ /**
+ * Opens subscription list (<code>i[n][q][f] --> i</code>) and resolves ref recursively to the topmost element,
+ * but not further than file borders (to prevent Stub to AST conversion)
+ *
+ * @param element element to open and resolve
+ * @return opened and resolved element
+ */
+ private static PsiElement handleSubscriptionsAndResolveSafely(PsiElement element) {
+ assert element != null;
+ if (element instanceof PySubscriptionExpression) {
+ element = ((PySubscriptionExpression)element).getRootOperand();
+ }
+ while (true) {
+ PsiReference reference = element.getReference();
+ if (reference == null) {
+ break;
+ }
+ PsiElement resolve = reference.resolve();
+ if (resolve == null || resolve.equals(element) || !PyUtil.inSameFile(resolve, element)) {
+ break;
+ }
+ element = resolve;
+ }
+ return element;
+ }
+
+ /**
+ * Checks if element is statement this inspection should work with
+ *
+ * @param element to check
+ * @return true if inspection should work with this element
+ */
+ private static boolean isRequiredStatement(PsiElement element) {
+ assert element != null;
+ return element instanceof PyWithStatement || element instanceof PyForStatement;
+ }
+}
diff --git a/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java b/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java
index 47f55a4..4af6767 100644
--- a/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java
@@ -20,7 +20,10 @@
import com.intellij.psi.PsiElementVisitor;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.*;
-import com.jetbrains.python.psi.types.*;
+import com.jetbrains.python.psi.types.PyClassType;
+import com.jetbrains.python.psi.types.PyType;
+import com.jetbrains.python.psi.types.PyTypeChecker;
+import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -89,7 +92,7 @@
@Nullable
private static Boolean isCallable(@NotNull PyExpression element, @NotNull TypeEvalContext context) {
- if (element instanceof PyQualifiedExpression && PyNames.CLASS.equals(element.getName())) {
+ if (element instanceof PyQualifiedExpression && PyNames.__CLASS__.equals(element.getName())) {
return true;
}
return PyTypeChecker.isCallable(context.getType(element));
diff --git a/python/src/com/jetbrains/python/inspections/PyMethodFirstArgAssignmentInspection.java b/python/src/com/jetbrains/python/inspections/PyMethodFirstArgAssignmentInspection.java
index bb5dfab..0d29a05 100644
--- a/python/src/com/jetbrains/python/inspections/PyMethodFirstArgAssignmentInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyMethodFirstArgAssignmentInspection.java
@@ -57,7 +57,7 @@
}
private void handleTarget(PyQualifiedExpression target, String name) {
- if (target.getQualifier() == null && name.equals(target.getText())) {
+ if (!target.isQualified() && name.equals(target.getText())) {
complain(target, name);
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyMissingConstructorInspection.java b/python/src/com/jetbrains/python/inspections/PyMissingConstructorInspection.java
index 0a4c362..9087180 100644
--- a/python/src/com/jetbrains/python/inspections/PyMissingConstructorInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyMissingConstructorInspection.java
@@ -139,7 +139,7 @@
if (args.length > 0) {
String firstArg = args[0].getText();
final String qualifiedName = cl.getQualifiedName();
- if (firstArg.equals(cl.getName()) || firstArg.equals(CANONICAL_SELF+"."+ CLASS) ||
+ if (firstArg.equals(cl.getName()) || firstArg.equals(CANONICAL_SELF+"."+ __CLASS__) ||
(qualifiedName != null && qualifiedName.endsWith(firstArg)))
return true;
for (PyClass s : cl.getAncestorClasses(myTypeEvalContext)) {
diff --git a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java
index 5a3bdce..ec37611 100644
--- a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java
@@ -41,7 +41,7 @@
import com.jetbrains.python.packaging.*;
import com.jetbrains.python.packaging.ui.PyChooseRequirementsDialog;
import com.jetbrains.python.psi.*;
-import com.jetbrains.python.psi.resolve.PyResolveUtil;
+import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -147,9 +147,8 @@
return;
}
}
- final List<PyExpression> expressions = PyResolveUtil.unwindQualifiers(importedExpression);
- if (!expressions.isEmpty()) {
- final PyExpression packageReferenceExpression = expressions.get(0);
+ final PyExpression packageReferenceExpression = PyPsiUtils.getFirstQualifier(importedExpression);
+ if (packageReferenceExpression != null) {
final String packageName = packageReferenceExpression.getName();
if (packageName != null && !myIgnoredPackages.contains(packageName)) {
if (!ApplicationManager.getApplication().isUnitTestMode() && !PyPIPackageUtil.INSTANCE.isInPyPI(packageName)) {
diff --git a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java b/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java
index 9b26d94..f3fddba 100644
--- a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java
@@ -22,9 +22,10 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
-import com.intellij.util.containers.hash.HashMap;
-import com.jetbrains.python.psi.*;
import com.intellij.psi.util.QualifiedName;
+import com.intellij.util.containers.hash.HashMap;
+import com.intellij.util.containers.hash.HashSet;
+import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.search.PySuperMethodsSearch;
import com.jetbrains.python.psi.types.PyModuleType;
import com.jetbrains.python.psi.types.PyType;
@@ -33,7 +34,9 @@
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
+import java.util.Collection;
import java.util.Map;
+import java.util.Set;
import java.util.regex.Pattern;
/**
@@ -68,9 +71,17 @@
public void visitPyAssignmentStatement(PyAssignmentStatement node) {
final PyFunction function = PsiTreeUtil.getParentOfType(node, PyFunction.class, true, PyClass.class);
if (function == null) return;
+ final Collection<PyGlobalStatement> globalStatements = PsiTreeUtil.findChildrenOfType(function, PyGlobalStatement.class);
+ final Set<String> globals = new HashSet<String>();
+ for (PyGlobalStatement statement : globalStatements) {
+ final PyTargetExpression[] statementGlobals = statement.getGlobals();
+ for (PyTargetExpression global : statementGlobals) {
+ globals.add(global.getName());
+ }
+ }
for (PyExpression expression : node.getTargets()) {
final String name = expression.getName();
- if (name == null) continue;
+ if (name == null || globals.contains(name)) continue;
if (expression instanceof PyTargetExpression) {
final PyExpression qualifier = ((PyTargetExpression)expression).getQualifier();
if (qualifier != null) {
@@ -126,7 +137,7 @@
final String asName = node.getAsName();
final QualifiedName importedQName = node.getImportedQName();
if (importedQName == null) return;
- final String name = importedQName.toString();
+ final String name = importedQName.getLastComponent();
if (asName == null || name == null) return;
if (UPPERCASE_REGEX.matcher(name).matches()) {
diff --git a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java
index 8daea863..fe9ac7f 100644
--- a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java
@@ -20,9 +20,10 @@
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.PyNames;
+import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyReferenceExpression;
@@ -67,20 +68,20 @@
if (qualifier == null || PyNames.CANONICAL_SELF.equals(qualifier.getText())) return;
final String name = node.getName();
if (name != null && name.startsWith("_") && !name.startsWith("__") && !name.endsWith("__")) {
- final PyClass parentClass = PsiTreeUtil.getParentOfType(node, PyClass.class);
+ final PyClass parentClass = getClassOwner(node);
if (parentClass != null) {
final PsiReference reference = node.getReference();
final PsiElement resolvedExpression = reference.resolve();
- final PyClass resolvedClass = PsiTreeUtil.getParentOfType(resolvedExpression, PyClass.class);
+ final PyClass resolvedClass = getClassOwner(resolvedExpression);
if (parentClass.isSubclass(resolvedClass))
return;
- PyClass outerClass = PsiTreeUtil.getParentOfType(parentClass, PyClass.class);
+ PyClass outerClass = getClassOwner(parentClass);
while (outerClass != null) {
if (outerClass.isSubclass(resolvedClass))
return;
- outerClass = PsiTreeUtil.getParentOfType(outerClass, PyClass.class);
+ outerClass = getClassOwner(outerClass);
}
}
final PyType type = myTypeEvalContext.getType(qualifier);
@@ -91,5 +92,14 @@
}
}
+ @Nullable
+ private static PyClass getClassOwner(@Nullable PsiElement element) {
+ for (ScopeOwner owner = ScopeUtil.getScopeOwner(element); owner != null; owner = ScopeUtil.getScopeOwner(owner)) {
+ if (owner instanceof PyClass) {
+ return (PyClass)owner;
+ }
+ }
+ return null;
+ }
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PySetFunctionToLiteralInspection.java b/python/src/com/jetbrains/python/inspections/PySetFunctionToLiteralInspection.java
index aaebc16b..f0bdeb3 100644
--- a/python/src/com/jetbrains/python/inspections/PySetFunctionToLiteralInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PySetFunctionToLiteralInspection.java
@@ -93,7 +93,7 @@
}
private static boolean isInBuiltins(PyExpression callee) {
- if (callee instanceof PyQualifiedExpression && (((PyQualifiedExpression)callee).getQualifier() != null)) {
+ if (callee instanceof PyQualifiedExpression && (((PyQualifiedExpression)callee).isQualified())) {
return false;
}
PsiReference reference = callee.getReference();
diff --git a/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java
index 8f6b5af..fa7a1b9 100644
--- a/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java
@@ -92,7 +92,7 @@
@Override
public void visitPyTargetExpression(@NotNull PyTargetExpression node) {
- if (node.getQualifier() == null) {
+ if (!node.isQualified()) {
processElement(node);
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java b/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java
index 82b3cdc..07f92ff 100644
--- a/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java
@@ -77,7 +77,7 @@
@Override
public void visitPyTargetExpression(@NotNull PyTargetExpression node) {
- if (node.getQualifier() == null) {
+ if (!node.isQualified()) {
processElement(node);
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java
index b35a6f75..5aec8ce 100644
--- a/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyStatementEffectInspection.java
@@ -79,7 +79,7 @@
if (checkStringLiteral(expression)) {
return;
}
- if (expression instanceof PyReferenceExpression && ((PyReferenceExpression)expression).getQualifier() == null) {
+ if (expression instanceof PyReferenceExpression && !((PyReferenceExpression)expression).isQualified()) {
registerProblem(expression, PyBundle.message("INSP.NAME.statement.message"));
}
else {
diff --git a/python/src/com/jetbrains/python/inspections/PyStringFormatParser.java b/python/src/com/jetbrains/python/inspections/PyStringFormatParser.java
index 5f935cf..158206c 100644
--- a/python/src/com/jetbrains/python/inspections/PyStringFormatParser.java
+++ b/python/src/com/jetbrains/python/inspections/PyStringFormatParser.java
@@ -29,11 +29,14 @@
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* @author yole
*/
public class PyStringFormatParser {
+ private static final Pattern NEW_STYLE_FORMAT_TOKENS = Pattern.compile("(\\{\\{)|(\\}\\})|(\\{[^\\{\\}]*\\})|([^\\{\\}]+)");
+
public static abstract class FormatStringChunk {
private final int myStartIndex;
protected int myEndIndex;
@@ -173,30 +176,22 @@
@NotNull
public static List<FormatStringChunk> parseNewStyleFormat(@NotNull String s) {
final List<FormatStringChunk> results = new ArrayList<FormatStringChunk>();
- int pos = 0;
- final int n = s.length();
- while (pos < n) {
- int next = s.indexOf('{', pos);
- while (next > 0 && next < n - 1 && s.charAt(next + 1) == '{') {
- next = s.indexOf('{', next + 2);
+ final Matcher matcher = NEW_STYLE_FORMAT_TOKENS.matcher(s);
+ while (matcher.find()) {
+ final String group = matcher.group();
+ final int start = matcher.start();
+ final int end = matcher.end();
+ if ("{{".equals(group)) {
+ results.add(new ConstantChunk(start, end));
}
- if (next < 0) {
- break;
+ else if ("}}".equals(group)) {
+ results.add(new ConstantChunk(start, end));
}
- if (next > pos) {
- results.add(new ConstantChunk(pos, next));
- }
- pos = next;
- next = s.indexOf('}', pos);
- while (next > 0 && next < n - 1 && s.charAt(next + 1) == '}') {
- next = s.indexOf('}', next + 2);
- }
- if (next > pos) {
- final SubstitutionChunk chunk = new SubstitutionChunk(pos);
- final int nameStart = pos + 1;
- final int chunkEnd = next + 1;
- chunk.setEndIndex(chunkEnd);
- final int nameEnd = StringUtil.indexOfAny(s, "!:.[}", nameStart, chunkEnd);
+ else if (group.startsWith("{") && group.endsWith("}")) {
+ final SubstitutionChunk chunk = new SubstitutionChunk(start);
+ chunk.setEndIndex(end);
+ final int nameStart = start + 1;
+ final int nameEnd = StringUtil.indexOfAny(s, "!:.[}", nameStart, end);
if (nameEnd > 0 && nameStart < nameEnd) {
final String name = s.substring(nameStart, nameEnd);
try {
@@ -209,10 +204,9 @@
// TODO: Parse substitution details
results.add(chunk);
}
- pos = next + 1;
- }
- if (pos < n) {
- results.add(new ConstantChunk(pos, n));
+ else {
+ results.add(new ConstantChunk(start, end));
+ }
}
return results;
}
diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java
index 484ac05..45df382 100644
--- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java
@@ -78,7 +78,7 @@
final PyExpression source = node.getForPart().getSource();
if (source != null) {
final PyType type = myTypeEvalContext.getType(source);
- if (type != null && !PyTypeChecker.isUnknown(type) && !PyABCUtil.isSubtype(type, PyNames.ITERABLE)) {
+ if (type != null && !PyTypeChecker.isUnknown(type) && !PyABCUtil.isSubtype(type, PyNames.ITERABLE, myTypeEvalContext)) {
registerProblem(source, String.format("Expected 'collections.Iterable', got '%s' instead",
PythonDocumentationProvider.getTypeName(type, myTypeEvalContext)));
}
diff --git a/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java b/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java
index 38b0a47..abec5b1 100644
--- a/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyUnboundLocalVariableInspection.java
@@ -79,7 +79,7 @@
return;
}
// Ignore qualifier inspections
- if (node.getQualifier() != null) {
+ if (node.isQualified()) {
return;
}
// Ignore import subelements
diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java
index 998530a..9e08a47 100644
--- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java
@@ -237,9 +237,9 @@
calls.add((PyCallExpression)cond);
}
if (cond != null) {
- final PyCallExpression[] callExprs = PsiTreeUtil.getChildrenOfType(cond, PyCallExpression.class);
- if (callExprs != null) {
- calls.addAll(Arrays.asList(callExprs));
+ final PyCallExpression[] callExpressions = PsiTreeUtil.getChildrenOfType(cond, PyCallExpression.class);
+ if (callExpressions != null) {
+ calls.addAll(Arrays.asList(callExpressions));
}
for (PyCallExpression call : calls) {
final PyExpression callee = call.getCallee();
@@ -427,9 +427,9 @@
}
final PsiElement element = reference.getElement();
final List<LocalQuickFix> actions = new ArrayList<LocalQuickFix>(2);
- final String refname = (element instanceof PyQualifiedExpression) ? ((PyQualifiedExpression)element).getReferencedName() : ref_text;
+ final String refName = (element instanceof PyQualifiedExpression) ? ((PyQualifiedExpression)element).getReferencedName() : ref_text;
// Empty text, nothing to highlight
- if (refname == null || refname.length() <= 0) {
+ if (refName == null || refName.length() <= 0) {
return;
}
@@ -449,47 +449,48 @@
}
}
// Legacy non-qualified ignore patterns
- if (myIgnoredIdentifiers.contains(refname)) {
+ if (myIgnoredIdentifiers.contains(refName)) {
return;
}
if (element instanceof PyReferenceExpression) {
- PyReferenceExpression refex = (PyReferenceExpression)element;
- if (PyNames.COMPARISON_OPERATORS.contains(refname)) {
+ PyReferenceExpression expr = (PyReferenceExpression)element;
+ if (PyNames.COMPARISON_OPERATORS.contains(refName)) {
return;
}
- if (refex.getQualifier() != null) {
+ if (expr.isQualified()) {
final PyClassTypeImpl object_type = (PyClassTypeImpl)PyBuiltinCache.getInstance(node).getObjectType();
- if ((object_type != null) && object_type.getPossibleInstanceMembers().contains(refname)) return;
+ if ((object_type != null) && object_type.getPossibleInstanceMembers().contains(refName)) return;
}
else {
- if (PyUnreachableCodeInspection.hasAnyInterruptedControlFlowPaths(refex)) {
+ if (PyUnreachableCodeInspection.hasAnyInterruptedControlFlowPaths(expr)) {
return;
}
if (LanguageLevel.forElement(node).isOlderThan(LanguageLevel.PYTHON26)) {
- if ("with".equals(refname)) {
+ if ("with".equals(refName)) {
actions.add(new UnresolvedRefAddFutureImportQuickFix());
}
}
if (ref_text.equals("true") || ref_text.equals("false")) {
actions.add(new UnresolvedRefTrueFalseQuickFix(element));
}
- addAddSelfFix(node, refex, actions);
+ addAddSelfFix(node, expr, actions);
PyCallExpression callExpression = PsiTreeUtil.getParentOfType(element, PyCallExpression.class);
- if (callExpression != null) {
- actions.add(new UnresolvedRefCreateFunctionQuickFix(callExpression, refex));
+ if (callExpression != null && (!(callExpression.getCallee() instanceof PyQualifiedExpression) ||
+ ((PyQualifiedExpression)callExpression.getCallee()).getQualifier() == null)) {
+ actions.add(new UnresolvedRefCreateFunctionQuickFix(callExpression, expr));
}
PyFunction parentFunction = PsiTreeUtil.getParentOfType(element, PyFunction.class);
PyDecorator decorator = PsiTreeUtil.getParentOfType(element, PyDecorator.class);
PyImportStatement importStatement = PsiTreeUtil.getParentOfType(element, PyImportStatement.class);
if (parentFunction != null && decorator == null && importStatement == null) {
- actions.add(new UnresolvedReferenceAddParameterQuickFix(refname));
+ actions.add(new UnresolvedReferenceAddParameterQuickFix(refName));
}
actions.add(new PyRenameUnresolvedRefQuickFix());
}
// unqualified:
// may be module's
- if (PyModuleType.getPossibleInstanceMembers().contains(refname)) return;
+ if (PyModuleType.getPossibleInstanceMembers().contains(refName)) return;
// may be a "try: import ..."; not an error not to resolve
if ((
PsiTreeUtil.getParentOfType(
@@ -512,31 +513,31 @@
if ("__qualname__".equals(ref_text) && LanguageLevel.forElement(element).isAtLeast(LanguageLevel.PYTHON33)) {
return;
}
- final PyQualifiedExpression qexpr = (PyQualifiedExpression)element;
- if (PyNames.COMPARISON_OPERATORS.contains(qexpr.getReferencedName()) || refname == null) {
+ final PyQualifiedExpression expr = (PyQualifiedExpression)element;
+ if (PyNames.COMPARISON_OPERATORS.contains(expr.getReferencedName())) {
return;
}
- final PyExpression qualifier = qexpr.getQualifier();
+ final PyExpression qualifier = expr.getQualifier();
if (qualifier != null) {
- PyType qtype = myTypeEvalContext.getType(qualifier);
- if (qtype != null) {
- if (ignoreUnresolvedMemberForType(qtype, reference, refname)) {
+ PyType type = myTypeEvalContext.getType(qualifier);
+ if (type != null) {
+ if (ignoreUnresolvedMemberForType(type, reference, refName)) {
return;
}
- addCreateMemberFromUsageFixes(qtype, reference, ref_text, actions);
- if (qtype instanceof PyClassTypeImpl) {
+ addCreateMemberFromUsageFixes(type, reference, ref_text, actions);
+ if (type instanceof PyClassTypeImpl) {
if (reference instanceof PyOperatorReference) {
description = PyBundle.message("INSP.unresolved.operator.ref",
- qtype.getName(), refname,
+ type.getName(), refName,
((PyOperatorReference)reference).getReadableOperatorName());
}
else {
- description = PyBundle.message("INSP.unresolved.ref.$0.for.class.$1", ref_text, qtype.getName());
+ description = PyBundle.message("INSP.unresolved.ref.$0.for.class.$1", ref_text, type.getName());
}
marked_qualified = true;
}
else {
- description = PyBundle.message("INSP.cannot.find.$0.in.$1", ref_text, qtype.getName());
+ description = PyBundle.message("INSP.cannot.find.$0.in.$1", ref_text, type.getName());
marked_qualified = true;
}
}
@@ -575,20 +576,9 @@
}
addPluginQuickFixes(reference, actions);
- final PsiElement point;
- final TextRange range;
- final PsiElement lastChild = node.getLastChild();
- if (reference instanceof PyOperatorReference || lastChild == null) {
- point = node;
- range = rangeInElement;
- }
- else {
- point = lastChild; // usually the identifier at the end of qual ref
- range = rangeInElement.shiftRight(-point.getStartOffsetInParent());
- }
- if (reference instanceof PyImportReference && refname != null) {
+ if (reference instanceof PyImportReference) {
// TODO: Ignore references in the second part of the 'from ... import ...' expression
- final QualifiedName qname = QualifiedName.fromDottedString(refname);
+ final QualifiedName qname = QualifiedName.fromDottedString(refName);
final List<String> components = qname.getComponents();
if (!components.isEmpty()) {
final String packageName = components.get(0);
@@ -605,7 +595,7 @@
}
}
}
- registerProblem(point, description, hl_type, null, range, actions.toArray(new LocalQuickFix[actions.size()]));
+ registerProblem(node, description, hl_type, null, rangeInElement, actions.toArray(new LocalQuickFix[actions.size()]));
}
/**
@@ -679,19 +669,19 @@
return null;
}
- private boolean ignoreUnresolvedMemberForType(@NotNull PyType qtype, PsiReference reference, String name) {
- if (qtype instanceof PyNoneType || PyTypeChecker.isUnknown(qtype)) {
+ private boolean ignoreUnresolvedMemberForType(@NotNull PyType type, PsiReference reference, String name) {
+ if (type instanceof PyNoneType || PyTypeChecker.isUnknown(type)) {
// this almost always means that we don't know the type, so don't show an error in this case
return true;
}
- if (qtype instanceof PyImportedModuleType) {
- PyImportedModule module = ((PyImportedModuleType)qtype).getImportedModule();
+ if (type instanceof PyImportedModuleType) {
+ PyImportedModule module = ((PyImportedModuleType)type).getImportedModule();
if (module.resolve() == null) {
return true;
}
}
- if (qtype instanceof PyClassTypeImpl) {
- PyClass cls = ((PyClassType)qtype).getPyClass();
+ if (type instanceof PyClassTypeImpl) {
+ PyClass cls = ((PyClassType)type).getPyClass();
if (overridesGetAttr(cls, myTypeEvalContext)) {
return true;
}
@@ -704,27 +694,27 @@
if (isDecoratedAsDynamic(cls, true)) {
return true;
}
- if (hasUnresolvedDynamicMember((PyClassType)qtype, reference, name)) return true;
+ if (hasUnresolvedDynamicMember((PyClassType)type, reference, name)) return true;
}
- if (qtype instanceof PyFunctionType) {
- final Callable callable = ((PyFunctionType)qtype).getCallable();
+ if (type instanceof PyFunctionType) {
+ final Callable callable = ((PyFunctionType)type).getCallable();
if (callable instanceof PyFunction && ((PyFunction)callable).getDecoratorList() != null) {
return true;
}
}
for (PyInspectionExtension extension : Extensions.getExtensions(PyInspectionExtension.EP_NAME)) {
- if (extension.ignoreUnresolvedMember(qtype, name)) {
+ if (extension.ignoreUnresolvedMember(type, name)) {
return true;
}
}
return false;
}
- private static boolean hasUnresolvedDynamicMember(@NotNull final PyClassType qtype,
+ private static boolean hasUnresolvedDynamicMember(@NotNull final PyClassType type,
PsiReference reference,
@NotNull final String name) {
for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) {
- final Collection<PyDynamicMember> resolveResult = provider.getMembers(qtype, reference.getElement());
+ final Collection<PyDynamicMember> resolveResult = provider.getMembers(type, reference.getElement());
for (PyDynamicMember member : resolveResult) {
if (member.getName().equals(name)) return true;
}
@@ -755,26 +745,26 @@
return false;
}
- private static void addCreateMemberFromUsageFixes(PyType qtype, PsiReference reference, String refText, List<LocalQuickFix> actions) {
+ private static void addCreateMemberFromUsageFixes(PyType type, PsiReference reference, String refText, List<LocalQuickFix> actions) {
PsiElement element = reference.getElement();
- if (qtype instanceof PyClassTypeImpl) {
- PyClass cls = ((PyClassType)qtype).getPyClass();
+ if (type instanceof PyClassTypeImpl) {
+ PyClass cls = ((PyClassType)type).getPyClass();
if (!PyBuiltinCache.getInstance(element).hasInBuiltins(cls)) {
if (element.getParent() instanceof PyCallExpression) {
- actions.add(new AddMethodQuickFix(refText, (PyClassType)qtype, true));
+ actions.add(new AddMethodQuickFix(refText, (PyClassType)type, true));
}
else if (!(reference instanceof PyOperatorReference)) {
- actions.add(new AddFieldQuickFix(refText, (PyClassType)qtype, "None"));
+ actions.add(new AddFieldQuickFix(refText, (PyClassType)type, "None"));
}
}
}
- else if (qtype instanceof PyModuleType) {
- PyFile file = ((PyModuleType)qtype).getModule();
+ else if (type instanceof PyModuleType) {
+ PyFile file = ((PyModuleType)type).getModule();
actions.add(new AddFunctionQuickFix(refText, file));
}
}
- private void addAddSelfFix(PyElement node, PyReferenceExpression refex, List<LocalQuickFix> actions) {
+ private void addAddSelfFix(PyElement node, PyReferenceExpression expr, List<LocalQuickFix> actions) {
final PyClass containedClass = PsiTreeUtil.getParentOfType(node, PyClass.class);
final PyFunction function = PsiTreeUtil.getParentOfType(node, PyFunction.class);
if (containedClass != null && function != null) {
@@ -782,29 +772,29 @@
if (parameters.length == 0) return;
final String qualifier = parameters[0].getText();
final PyDecoratorList decoratorList = function.getDecoratorList();
- boolean isClassmethod = false;
+ boolean isClassMethod = false;
if (decoratorList != null) {
for (PyDecorator decorator : decoratorList.getDecorators()) {
final PyExpression callee = decorator.getCallee();
if (callee != null && PyNames.CLASSMETHOD.equals(callee.getText()))
- isClassmethod = true;
+ isClassMethod = true;
}
}
for (PyTargetExpression target : containedClass.getInstanceAttributes()) {
- if (!isClassmethod && Comparing.strEqual(node.getName(), target.getName())) {
- actions.add(new UnresolvedReferenceAddSelfQuickFix(refex, qualifier));
+ if (!isClassMethod && Comparing.strEqual(node.getName(), target.getName())) {
+ actions.add(new UnresolvedReferenceAddSelfQuickFix(expr, qualifier));
}
}
for (PyStatement statement : containedClass.getStatementList().getStatements()) {
if (statement instanceof PyAssignmentStatement) {
PyExpression lhsExpression = ((PyAssignmentStatement)statement).getLeftHandSideExpression();
- if (lhsExpression != null && lhsExpression.getText().equals(refex.getText())) {
- PyExpression callexpr = ((PyAssignmentStatement)statement).getAssignedValue();
- if (callexpr instanceof PyCallExpression) {
- PyType type = myTypeEvalContext.getType(callexpr);
+ if (lhsExpression != null && lhsExpression.getText().equals(expr.getText())) {
+ PyExpression assignedValue = ((PyAssignmentStatement)statement).getAssignedValue();
+ if (assignedValue instanceof PyCallExpression) {
+ PyType type = myTypeEvalContext.getType(assignedValue);
if (type != null && type instanceof PyClassTypeImpl) {
- if (((PyCallExpression)callexpr).isCalleeText(PyNames.PROPERTY)) {
- actions.add(new UnresolvedReferenceAddSelfQuickFix(refex, qualifier));
+ if (((PyCallExpression)assignedValue).isCalleeText(PyNames.PROPERTY)) {
+ actions.add(new UnresolvedReferenceAddSelfQuickFix(expr, qualifier));
}
}
}
@@ -812,8 +802,8 @@
}
}
for (PyFunction method : containedClass.getMethods()) {
- if (refex.getText().equals(method.getName())) {
- actions.add(new UnresolvedReferenceAddSelfQuickFix(refex, qualifier));
+ if (expr.getText().equals(method.getName())) {
+ actions.add(new UnresolvedReferenceAddSelfQuickFix(expr, qualifier));
}
}
}
@@ -855,9 +845,9 @@
PsiTreeUtil.getParentOfType(element, PyImportStatementBase.class) == null) {
PsiElement anchor = element;
if (element instanceof PyQualifiedExpression) {
- final PyExpression qexpr = ((PyQualifiedExpression)element).getQualifier();
- if (qexpr != null) {
- final PyType type = myTypeEvalContext.getType(qexpr);
+ final PyExpression expr = ((PyQualifiedExpression)element).getQualifier();
+ if (expr != null) {
+ final PyType type = myTypeEvalContext.getType(expr);
if (type instanceof PyModuleType) {
anchor = ((PyModuleType)type).getModule();
}
@@ -925,7 +915,7 @@
if (myAllImports.isEmpty()) {
return Collections.emptyList();
}
- // PY-1315 Unused imports inspection shouldn't work in python repl console
+ // PY-1315 Unused imports inspection shouldn't work in python REPL console
final NameDefiner first = myAllImports.iterator().next();
if (first.getContainingFile() instanceof PyExpressionCodeFragment || PydevConsoleRunner.isInPydevConsole(first)) {
return Collections.emptyList();
@@ -984,6 +974,10 @@
final PyImportElement importElement = (PyImportElement)unusedImport;
final PsiElement element = importElement.resolve();
if (element == null) {
+ if (importElement.getImportedQName() != null) {
+ //Mark import as unused even if it can't be resolved
+ result.add(importElement.getParent());
+ }
continue;
}
if (dunderAll != null && dunderAll.contains(importElement.getVisibleName())) {
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java
index b3e9e2d..2306a47 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java
@@ -149,15 +149,15 @@
for (int i = 1; i != parameters.length; i++) {
PyParameter p = parameters[i];
if (p.getDefaultValue() != null) continue;
- String param;
- param = p.getText();
- if (param.startsWith("**")) {
+ final String param = p.getName();
+ String paramText = p.getText();
+ if (paramText.startsWith("**")) {
addDouble = true;
if (doubleStarName == null)
doubleStarName = p.getText();
continue;
}
- if (param.startsWith("*")) {
+ if (paramText.startsWith("*")) {
addStar = true;
if (starName == null)
starName = p.getText();
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddFunctionQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddFunctionQuickFix.java
index fbd22d7..4d71b42 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/AddFunctionQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/AddFunctionQuickFix.java
@@ -66,9 +66,7 @@
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
try {
- // descriptor points to the unresolved identifier
- // there can be no name clash, else the name would have resolved, and it hasn't.
- PsiElement problem_elt = descriptor.getPsiElement().getParent(); // id -> ref expr
+ final PsiElement problem_elt = descriptor.getPsiElement();
sure(myPyFile);
sure(FileModificationService.getInstance().preparePsiElementForWrite(myPyFile));
// try to at least match parameter count
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java
index f2246b1..30d9910 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java
@@ -67,9 +67,8 @@
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
try {
- // descriptor points to the unresolved identifier
// there can be no name clash, else the name would have resolved, and it hasn't.
- PsiElement problem_elt = descriptor.getPsiElement().getParent(); // id -> ref expr
+ PsiElement problem_elt = descriptor.getPsiElement();
PyClass cls = myQualifierType.getPyClass();
boolean call_by_class = myQualifierType.isDefinition();
String item_name = myIdentifier;
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/ConvertDictCompQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/ConvertDictCompQuickFix.java
index 45f20be..67a2bdd 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/ConvertDictCompQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/ConvertDictCompQuickFix.java
@@ -52,16 +52,38 @@
}
private static void replaceComprehension(Project project, PyDictCompExpression expression) {
- List<ComprhForComponent> forComponents = expression.getForComponents();
if (expression.getResultExpression() instanceof PyKeyValueExpression) {
- PyKeyValueExpression keyValueExpression = (PyKeyValueExpression)expression.getResultExpression();
- PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
+ final PyKeyValueExpression keyValueExpression = (PyKeyValueExpression)expression.getResultExpression();
+ final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
assert keyValueExpression.getValue() != null;
- expression.replace(elementGenerator.createFromText(LanguageLevel.getDefault(), PyExpressionStatement.class,
- "dict([(" + keyValueExpression.getKey().getText() + ", " +
- keyValueExpression.getValue().getText() + ") for " +
- forComponents.get(0).getIteratorVariable().getText() + " in " +
- forComponents.get(0).getIteratedList().getText() + "])"));
+
+ final List<ComprehensionComponent> components = expression.getComponents();
+ final StringBuilder replacement = new StringBuilder("dict([(" + keyValueExpression.getKey().getText() + ", " +
+ keyValueExpression.getValue().getText() + ")");
+ int slashNum = 1;
+ for (ComprehensionComponent component : components) {
+ if (component instanceof ComprhForComponent) {
+ replacement.append("for ");
+ replacement.append(((ComprhForComponent)component).getIteratorVariable().getText());
+ replacement.append(" in ");
+ replacement.append(((ComprhForComponent)component).getIteratedList().getText());
+ replacement.append(" ");
+ }
+ if (component instanceof ComprhIfComponent) {
+ final PyExpression test = ((ComprhIfComponent)component).getTest();
+ if (test != null) {
+ replacement.append("if ");
+ replacement.append(test.getText());
+ replacement.append(" ");
+ }
+ }
+ for (int i = 0; i != slashNum; ++i)
+ replacement.append("\t");
+ ++slashNum;
+ }
+ replacement.append("])");
+
+ expression.replace(elementGenerator.createFromText(LanguageLevel.getDefault(), PyExpressionStatement.class, replacement.toString()));
}
}
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyRenameUnresolvedRefQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyRenameUnresolvedRefQuickFix.java
index 4726aaae..ec198aa 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/PyRenameUnresolvedRefQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/PyRenameUnresolvedRefQuickFix.java
@@ -30,7 +30,6 @@
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.ResolveResult;
-import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
@@ -65,8 +64,10 @@
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
- final PyReferenceExpression referenceExpression = PsiTreeUtil.getParentOfType(element, PyReferenceExpression.class);
- if (referenceExpression == null) return;
+ if (!(element instanceof PyReferenceExpression)) {
+ return;
+ }
+ final PyReferenceExpression referenceExpression = (PyReferenceExpression)element;
ScopeOwner parentScope = ScopeUtil.getScopeOwner(referenceExpression);
if (parentScope == null) return;
diff --git a/python/src/com/jetbrains/python/parsing/StatementParsing.java b/python/src/com/jetbrains/python/parsing/StatementParsing.java
index 641eb39..655fadc 100644
--- a/python/src/com/jetbrains/python/parsing/StatementParsing.java
+++ b/python/src/com/jetbrains/python/parsing/StatementParsing.java
@@ -767,7 +767,7 @@
if (myBuilder.getTokenType() == PyTokenTypes.AS_KEYWORD) {
myBuilder.advanceLexer();
if (!getExpressionParser().parseSingleExpression(true)) {
- myBuilder.error("identifier expected");
+ myBuilder.error("Identifier expected");
// 'as' is followed by a target
}
}
diff --git a/python/src/com/jetbrains/python/patterns/PythonPatterns.java b/python/src/com/jetbrains/python/patterns/PythonPatterns.java
index f4ce5e7..1ce1d75 100644
--- a/python/src/com/jetbrains/python/patterns/PythonPatterns.java
+++ b/python/src/com/jetbrains/python/patterns/PythonPatterns.java
@@ -22,11 +22,14 @@
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.documentation.DocStringUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.Nullable;
+import java.util.regex.Pattern;
+
/**
* @author yole
*/
@@ -39,6 +42,23 @@
});
}
+ public static PyElementPattern.Capture<PyStringLiteralExpression> pyStringLiteralMatches(final String regexp) {
+ final Pattern pattern = Pattern.compile(regexp, Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
+ return new PyElementPattern.Capture<PyStringLiteralExpression>(new InitialPatternCondition<PyStringLiteralExpression>(PyStringLiteralExpression.class) {
+ @Override
+ public boolean accepts(@Nullable Object o, ProcessingContext context) {
+ if (o instanceof PyStringLiteralExpression) {
+ final PyStringLiteralExpression expr = (PyStringLiteralExpression)o;
+ if (!DocStringUtil.isDocStringExpression(expr)) {
+ final String value = expr.getStringValue();
+ return pattern.matcher(value).matches();
+ }
+ }
+ return false;
+ }
+ });
+ }
+
public static PyElementPattern.Capture<PyExpression> pyArgument(final String functionName, final int index) {
return new PyElementPattern.Capture<PyExpression>(new InitialPatternCondition<PyExpression>(PyExpression.class) {
public boolean accepts(@Nullable final Object o, final ProcessingContext context) {
diff --git a/python/src/com/jetbrains/python/psi/PyFileElementType.java b/python/src/com/jetbrains/python/psi/PyFileElementType.java
index 07d87c9..150745e 100644
--- a/python/src/com/jetbrains/python/psi/PyFileElementType.java
+++ b/python/src/com/jetbrains/python/psi/PyFileElementType.java
@@ -63,7 +63,7 @@
@Override
public int getStubVersion() {
// Don't forget to update versions of indexes that use the updated stub-based elements
- return 48;
+ return 49;
}
@Nullable
diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java
index 0cd2994..bcaf70d 100644
--- a/python/src/com/jetbrains/python/psi/PyUtil.java
+++ b/python/src/com/jetbrains/python/psi/PyUtil.java
@@ -61,8 +61,6 @@
import com.jetbrains.python.codeInsight.stdlib.PyNamedTupleType;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.jetbrains.python.psi.impl.PyPsiUtils;
-import com.jetbrains.python.psi.resolve.PyResolveContext;
-import com.jetbrains.python.psi.resolve.QualifiedResolveResult;
import com.jetbrains.python.psi.types.*;
import com.jetbrains.python.refactoring.classes.extractSuperclass.PyExtractSuperclassHelper;
import org.jetbrains.annotations.NonNls;
@@ -415,7 +413,7 @@
PyExpression qualifier = ref.getQualifier();
if (qualifier != null) {
String attr_name = ref.getReferencedName();
- if (PyNames.CLASS.equals(attr_name)) {
+ if (PyNames.__CLASS__.equals(attr_name)) {
PyType qualifierType = context.getType(qualifier);
if (qualifierType instanceof PyClassType) {
return new PyClassTypeImpl(((PyClassType)qualifierType).getPyClass(), true); // always as class, never instance
@@ -700,14 +698,11 @@
return false;
}
for (PyDecorator decorator : decoratorList.getDecorators()) {
- final PyExpression callee = decorator.getCallee();
- if (callee instanceof PyReferenceExpression) {
- final PsiReference reference = callee.getReference();
- if (reference == null) continue;
- final PsiElement resolved = reference.resolve();
- if (resolved instanceof PyQualifiedNameOwner) {
- final String name = ((PyQualifiedNameOwner)resolved).getQualifiedName();
- return PyNames.ABSTRACTMETHOD.equals(name) || PyNames.ABSTRACTPROPERTY.equals(name);
+ final QualifiedName qualifiedName = decorator.getQualifiedName();
+ if (qualifiedName != null) {
+ final String name = qualifiedName.toString();
+ if (name.endsWith(PyNames.ABSTRACTMETHOD) || name.endsWith(PyNames.ABSTRACTPROPERTY)) {
+ return true;
}
}
}
@@ -1114,7 +1109,7 @@
PyExpression[] args = node.getArguments();
if (args.length > 0) {
String firstArg = args[0].getText();
- if (firstArg.equals(klass.getName()) || firstArg.equals(PyNames.CANONICAL_SELF + "." + PyNames.CLASS)) {
+ if (firstArg.equals(klass.getName()) || firstArg.equals(PyNames.CANONICAL_SELF + "." + PyNames.__CLASS__)) {
return true;
}
for (PyClass s : klass.getAncestorClasses()) {
@@ -1204,49 +1199,6 @@
}
@Nullable
- public static PyClass getMetaClass(@NotNull final PyClass pyClass) {
- final PyTargetExpression metaClassAttribute = pyClass.findClassAttribute(PyNames.DUNDER_METACLASS, false);
- if (metaClassAttribute != null) {
- final PyExpression expression = metaClassAttribute.findAssignedValue();
- final PyClass metaclass = getMetaFromExpression(expression);
- if (metaclass != null) return metaclass;
- }
- final PsiFile containingFile = pyClass.getContainingFile();
- if (containingFile instanceof PyFile) {
- final PsiElement element = ((PyFile)containingFile).getElementNamed(PyNames.DUNDER_METACLASS);
- if (element instanceof PyTargetExpression) {
- final PyExpression expression = ((PyTargetExpression)element).findAssignedValue();
- final PyClass metaclass = getMetaFromExpression(expression);
- if (metaclass != null) return metaclass;
- }
- }
-
- if (LanguageLevel.forElement(pyClass).isPy3K()) {
- final PyExpression[] superClassExpressions = pyClass.getSuperClassExpressions();
- for (PyExpression superClassExpression : superClassExpressions) {
- if (superClassExpression instanceof PyKeywordArgument &&
- PyNames.METACLASS.equals(((PyKeywordArgument)superClassExpression).getKeyword())) {
- final PyExpression expression = ((PyKeywordArgument)superClassExpression).getValueExpression();
- final PyClass metaclass = getMetaFromExpression(expression);
- if (metaclass != null) return metaclass;
- }
- }
- }
- return null;
- }
-
- @Nullable
- private static PyClass getMetaFromExpression(final PyExpression metaclass) {
- if (metaclass instanceof PyReferenceExpression) {
- final QualifiedResolveResult result = ((PyReferenceExpression)metaclass).followAssignmentsChain(PyResolveContext.noImplicits());
- if (result.getElement() instanceof PyClass) {
- return (PyClass)result.getElement();
- }
- }
- return null;
- }
-
- @Nullable
public static PsiElement findPrevAtOffset(PsiFile psiFile, int caretOffset, Class ... toSkip) {
PsiElement element = psiFile.findElementAt(caretOffset);
if (element == null || caretOffset < 0) {
@@ -1396,7 +1348,7 @@
private static int optionalParametersCount(@NotNull List<PyParameter> parameters) {
int n = 0;
for (PyParameter parameter : parameters) {
- if (parameter.getDefaultValue() != null) {
+ if (parameter.hasDefaultValue()) {
n++;
}
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PropertyBunch.java b/python/src/com/jetbrains/python/psi/impl/PropertyBunch.java
index 64f8986..59cc287 100644
--- a/python/src/com/jetbrains/python/psi/impl/PropertyBunch.java
+++ b/python/src/com/jetbrains/python/psi/impl/PropertyBunch.java
@@ -74,7 +74,7 @@
PyExpression callee = call.getCallee();
if (callee instanceof PyReferenceExpression) {
PyReferenceExpression ref = (PyReferenceExpression)callee;
- if (ref.getQualifier() != null) return null;
+ if (ref.isQualified()) return null;
if (PyNames.PROPERTY.equals(callee.getName())) {
PsiFile file = source.getContainingFile();
if (isBuiltinFile(file) || !resolvesLocally(ref)) {
diff --git a/python/src/com/jetbrains/python/psi/impl/PyAssignmentStatementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyAssignmentStatementImpl.java
index 1ee93e2..9f76798 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyAssignmentStatementImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyAssignmentStatementImpl.java
@@ -209,7 +209,7 @@
final List<PyExpression> expressions = PyUtil.flattenedParensAndStars(getTargets());
List<PyElement> result = new ArrayList<PyElement>();
for (PyExpression expression : expressions) {
- if (expression instanceof PyQualifiedExpression && ((PyQualifiedExpression)expression).getQualifier() != null) {
+ if (expression instanceof PyQualifiedExpression && ((PyQualifiedExpression)expression).isQualified()) {
continue;
}
result.add(expression);
@@ -223,7 +223,7 @@
PyExpression[] targets = getTargets();
if (targets.length == 1 && targets[0] instanceof PyTargetExpression) {
PyTargetExpression target = (PyTargetExpression)targets[0];
- return target.getQualifier() == null && the_name.equals(target.getName()) ? target : null;
+ return !target.isQualified() && the_name.equals(target.getName()) ? target : null;
}
return IterHelper.findName(iterateNames(), the_name);
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java
index 095e322..bee876a 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java
@@ -20,10 +20,14 @@
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.QualifiedName;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyNames;
-import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.PyBinaryExpression;
+import com.jetbrains.python.psi.PyElementType;
+import com.jetbrains.python.psi.PyElementVisitor;
+import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.impl.references.PyOperatorReference;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.types.*;
@@ -149,6 +153,17 @@
return getLeftExpression();
}
+ @Nullable
+ @Override
+ public QualifiedName asQualifiedName() {
+ return PyPsiUtils.asQualifiedName(this);
+ }
+
+ @Override
+ public boolean isQualified() {
+ return getQualifier() != null;
+ }
+
@Override
public String getReferencedName() {
final PyElementType t = getOperator();
diff --git a/python/src/com/jetbrains/python/psi/impl/PyBlockEvaluator.java b/python/src/com/jetbrains/python/psi/impl/PyBlockEvaluator.java
index 83b2949..c561eb6 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyBlockEvaluator.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyBlockEvaluator.java
@@ -93,7 +93,7 @@
public void visitPyAugAssignmentStatement(PyAugAssignmentStatement node) {
PyExpression target = node.getTarget();
String name = target.getName();
- if (target instanceof PyReferenceExpression && ((PyReferenceExpression)target).getQualifier() == null && name != null) {
+ if (target instanceof PyReferenceExpression && !((PyReferenceExpression)target).isQualified() && name != null) {
Object currentValue = myNamespace.get(name);
if (currentValue != null) {
Object rhs = prepareEvaluator().evaluate(node.getValue());
@@ -121,7 +121,7 @@
PyExpression qualifier = calleeRef.getQualifier();
if (qualifier instanceof PyReferenceExpression) {
PyReferenceExpression qualifierRef = (PyReferenceExpression)qualifier;
- if (qualifierRef.getQualifier() == null) {
+ if (!qualifierRef.isQualified()) {
if (PyNames.EXTEND.equals(calleeRef.getReferencedName()) && node.getArguments().length == 1) {
processExtendCall(node, qualifierRef.getReferencedName());
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
index 506fdb0..bd33be4 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java
@@ -490,7 +490,7 @@
if (first_arg instanceof PyReferenceExpression) {
final PyReferenceExpression firstArgRef = (PyReferenceExpression)first_arg;
final PyExpression qualifier = firstArgRef.getQualifier();
- if (qualifier != null && PyNames.CLASS.equals(firstArgRef.getReferencedName())) {
+ if (qualifier != null && PyNames.__CLASS__.equals(firstArgRef.getReferencedName())) {
final PsiReference qRef = qualifier.getReference();
final PsiElement element = qRef == null ? null : qRef.resolve();
if (element instanceof PyParameter) {
diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
index 47fb347..877e5fb 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
@@ -1169,6 +1169,64 @@
return manager.getParameterizedCachedValue(this, myCachedValueKey, myCachedAncestorsProvider, false, context);
}
+ @Nullable
+ @Override
+ public PyClassLikeType getMetaClassType(@NotNull TypeEvalContext context) {
+ if (context.maySwitchToAST(this)) {
+ final PyExpression expression = getMetaClassExpression();
+ if (expression != null) {
+ final PyType type = context.getType(expression);
+ if (type instanceof PyClassLikeType) {
+ return (PyClassLikeType)type;
+ }
+ }
+ }
+ else {
+ final PyClassStub stub = getStub();
+ final QualifiedName name = stub != null ? stub.getMetaClass() : PyPsiUtils.asQualifiedName(getMetaClassExpression());
+ final PsiFile file = getContainingFile();
+ if (file instanceof PyFile) {
+ final PyFile pyFile = (PyFile)file;
+ if (name != null) {
+ return classTypeFromQName(name, pyFile, context);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public PyExpression getMetaClassExpression() {
+ final LanguageLevel level = LanguageLevel.forElement(this);
+ if (level.isAtLeast(LanguageLevel.PYTHON30)) {
+ // Requires AST access
+ for (PyExpression expression : getSuperClassExpressions()) {
+ if (expression instanceof PyKeywordArgument) {
+ final PyKeywordArgument argument = (PyKeywordArgument)expression;
+ if (PyNames.METACLASS.equals(argument.getKeyword())) {
+ return argument.getValueExpression();
+ }
+ }
+ }
+ }
+ else {
+ final PyTargetExpression attribute = findClassAttribute(PyNames.DUNDER_METACLASS, false);
+ if (attribute != null) {
+ return attribute;
+ }
+ final PsiFile file = getContainingFile();
+ if (file instanceof PyFile) {
+ final PyFile pyFile = (PyFile)file;
+ final PsiElement element = pyFile.getElementNamed(PyNames.DUNDER_METACLASS);
+ if (element instanceof PyExpression) {
+ return (PyExpression)element;
+ }
+ }
+ }
+ return null;
+ }
+
@NotNull
private List<PyClassLikeType> getMROAncestorTypes(@NotNull TypeEvalContext context) {
final PyType thisType = context.getType(this);
diff --git a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java
index f64b533..92e75ed 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java
@@ -26,7 +26,6 @@
import com.jetbrains.python.PythonDialectsTokenSetProvider;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
-import com.jetbrains.python.psi.resolve.PyResolveUtil;
import com.jetbrains.python.psi.stubs.PyDecoratorStub;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
@@ -34,8 +33,6 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.List;
-
/**
* @author dcheryasov
*/
@@ -84,13 +81,9 @@
return stub.getQualifiedName();
}
else {
- PyReferenceExpression node = PsiTreeUtil.getChildOfType(this, PyReferenceExpression.class);
+ final PyReferenceExpression node = PsiTreeUtil.getChildOfType(this, PyReferenceExpression.class);
if (node != null) {
- List<PyExpression> parts = PyResolveUtil.unwindQualifiers(node);
- if (parts != null) {
- //Collections.reverse(parts);
- return PyQualifiedNameFactory.fromReferenceChain(parts);
- }
+ return node.asQualifiedName();
}
return null;
}
@@ -122,7 +115,7 @@
@Override
public <T extends PsiElement> T getArgument(int index, Class<T> argClass) {
PyExpression[] args = getArguments();
- return args.length >= index && argClass.isInstance(args[index]) ? argClass.cast(args[index]) : null;
+ return args.length > index && argClass.isInstance(args[index]) ? argClass.cast(args[index]) : null;
}
@Override
diff --git a/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java b/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java
index db114df..321ffc4 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java
@@ -105,7 +105,7 @@
}
protected Object evaluateReferenceExpression(PyReferenceExpression expr) {
- if (expr.getQualifier() == null) {
+ if (!expr.isQualified()) {
if (myNamespace != null) {
return myNamespace.get(expr.getReferencedName());
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyExceptPartImpl.java b/python/src/com/jetbrains/python/psi/impl/PyExceptPartImpl.java
index 812072d..c051d1b 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyExceptPartImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyExceptPartImpl.java
@@ -63,6 +63,7 @@
}
public PyElement getElementNamed(final String the_name) {
+ // Requires switching from stubs to AST in getTarget()
return IterHelper.findName(iterateNames(), the_name);
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
index f16850e..68aaa79 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java
@@ -614,7 +614,7 @@
@Nullable
private List<String> getStringListFromValue(PyExpression expression) {
- if (expression instanceof PyReferenceExpression && ((PyReferenceExpression)expression).getQualifier() == null) {
+ if (expression instanceof PyReferenceExpression && !((PyReferenceExpression)expression).isQualified()) {
return myDunderLike.get(((PyReferenceExpression)expression).getReferencedName());
}
return PyUtil.strListValue(expression);
diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java
index ddeaf12..70e3ecf 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java
@@ -28,7 +28,6 @@
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PythonDialectsTokenSetProvider;
import com.jetbrains.python.psi.*;
-import com.jetbrains.python.psi.resolve.PyResolveUtil;
import com.jetbrains.python.psi.resolve.ResolveImportUtil;
import com.jetbrains.python.psi.stubs.PyImportElementStub;
import org.jetbrains.annotations.NotNull;
@@ -36,7 +35,6 @@
import javax.swing.*;
import java.util.Collections;
-import java.util.List;
/**
* The "import foo" or "import foo as bar" parts.
@@ -150,7 +148,7 @@
buf.append("from ");
PyReferenceExpression imp_src = ((PyFromImportStatement)elt).getImportSource();
if (imp_src != null) {
- buf.append(PyResolveUtil.toPath(imp_src));
+ buf.append(PyPsiUtils.toPath(imp_src));
}
else {
buf.append("<?>");
@@ -185,10 +183,7 @@
if (ret == null) {
final PyReferenceExpression importReference = getImportReferenceExpression();
if (importReference != null) {
- final List<PyExpression> qualifiers = PyResolveUtil.unwindQualifiers(importReference);
- if (qualifiers.size() > 0) {
- ret = qualifiers.get(0);
- }
+ ret = PyPsiUtils.getFirstQualifier(importReference);
}
}
if (ret == null) {
diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
index b0a0367..9c34062 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
@@ -31,6 +31,8 @@
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDialectsTokenSetProvider;
+import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.stubs.PyNamedParameterStub;
@@ -298,9 +300,9 @@
@NotNull
@Override
public SearchScope getUseScope() {
- PyFunction func = PsiTreeUtil.getParentOfType(this, PyFunction.class);
- if (func != null) {
- return new LocalSearchScope(func);
+ final ScopeOwner owner = ScopeUtil.getScopeOwner(this);
+ if (owner instanceof PyFunction) {
+ return new LocalSearchScope(owner);
}
return new LocalSearchScope(getContainingFile());
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyPathEvaluator.java b/python/src/com/jetbrains/python/psi/impl/PyPathEvaluator.java
index d5e1527..7a22165 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyPathEvaluator.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyPathEvaluator.java
@@ -85,7 +85,7 @@
else if (PyNames.CURDIR.equals(expr.getName())) {
return ".";
}
- if (expr.getQualifier() == null && PyNames.FILE.equals(expr.getReferencedName())) {
+ if (!expr.isQualified() && PyNames.FILE.equals(expr.getReferencedName())) {
return myContainingFilePath;
}
return super.evaluateReferenceExpression(expr);
diff --git a/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java
index 946e719..71658f0 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyPrefixExpressionImpl.java
@@ -19,6 +19,7 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.PsiReference;
+import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
@@ -98,6 +99,17 @@
return getOperand();
}
+ @Nullable
+ @Override
+ public QualifiedName asQualifiedName() {
+ return PyPsiUtils.asQualifiedName(this);
+ }
+
+ @Override
+ public boolean isQualified() {
+ return getQualifier() != null;
+ }
+
@Override
public String getReferencedName() {
PyElementType t = getOperator();
diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java
index 455d4c5..c5e60eb 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java
@@ -50,6 +50,7 @@
*/
public class PyReferenceExpressionImpl extends PyElementImpl implements PyReferenceExpression {
private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.psi.impl.PyReferenceExpressionImpl");
+ private QualifiedName myQualifiedName = null;
public PyReferenceExpressionImpl(ASTNode astNode) {
super(astNode);
@@ -99,6 +100,11 @@
return (PyExpression)(nodes.length == 1 ? nodes[0].getPsi() : null);
}
+ @Override
+ public boolean isQualified() {
+ return getQualifier() != null;
+ }
+
@Nullable
public String getReferencedName() {
final ASTNode nameElement = getNameElement();
@@ -173,7 +179,10 @@
@Nullable
public QualifiedName asQualifiedName() {
- return PyQualifiedNameFactory.fromReferenceChain(PyResolveUtil.unwindQualifiers(this));
+ if (myQualifiedName == null) {
+ myQualifiedName = PyPsiUtils.asQualifiedName(this);
+ }
+ return myQualifiedName;
}
@Override
@@ -186,8 +195,8 @@
return null;
}
try {
- final PyExpression qualifier = getQualifier();
- if (qualifier == null) {
+ final boolean qualified = isQualified();
+ if (!qualified) {
String name = getReferencedName();
if (PyNames.NONE.equals(name)) {
return PyNoneType.INSTANCE;
@@ -197,7 +206,7 @@
if (type != null) {
return type;
}
- if (qualifier != null) {
+ if (qualified) {
PyType maybe_type = PyUtil.getSpecialAttributeType(this, context);
if (maybe_type != null) return maybe_type;
Ref<PyType> typeOfProperty = getTypeOfProperty(context);
@@ -404,6 +413,12 @@
return null;
}
+ @Override
+ public void subtreeChanged() {
+ super.subtreeChanged();
+ myQualifiedName = null;
+ }
+
private static class QualifiedResolveResultImpl extends RatedResolveResult implements QualifiedResolveResult {
// a trivial implementation
private List<PyExpression> myQualifiers;
diff --git a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java
index a30a2de..307ac8e 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java
@@ -22,7 +22,6 @@
import com.intellij.util.containers.HashSet;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
-import com.jetbrains.python.psi.resolve.PyResolveUtil;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.psi.types.PyModuleType;
import com.jetbrains.python.toolbox.ChainIterable;
@@ -101,7 +100,7 @@
if (elt != null) { // always? who knows :)
PyReferenceExpression imp_src = elt.getImportSource();
if (imp_src != null) {
- return PyResolveUtil.toPath(imp_src);
+ return PyPsiUtils.toPath(imp_src);
}
}
return "<?>";
diff --git a/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java
index 7595fde..340ae09 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java
@@ -145,7 +145,19 @@
private static boolean isUnicode(String text) {
return text.length() > 0 && Character.toUpperCase(text.charAt(0)) == 'U'; //TODO[ktisha]
- }
+ }
+
+ private boolean isUnicodeByDefault() {
+ if (LanguageLevel.forElement(this).isAtLeast(LanguageLevel.PYTHON30)) {
+ return true;
+ }
+ final PsiFile file = getContainingFile();
+ if (file instanceof PyFile) {
+ final PyFile pyFile = (PyFile)file;
+ return pyFile.hasImportFromFuture(FutureFeature.UNICODE_LITERALS);
+ }
+ return false;
+ }
private static boolean isBytes(String text) {
return text.length() > 0 && Character.toUpperCase(text.charAt(0)) == 'B';
@@ -161,12 +173,13 @@
if (myDecodedFragments == null) {
final List<Pair<TextRange, String>> result = new ArrayList<Pair<TextRange, String>>();
final int elementStart = getTextRange().getStartOffset();
+ final boolean unicodeByDefault = isUnicodeByDefault();
for (ASTNode node : getStringNodes()) {
final String text = node.getText();
final TextRange textRange = getNodeTextRange(text);
final int offset = node.getTextRange().getStartOffset() - elementStart + textRange.getStartOffset();
final String encoded = textRange.substring(text);
- result.addAll(getDecodedFragments(encoded, offset, isRaw(text), isUnicode(text)));
+ result.addAll(getDecodedFragments(encoded, offset, isRaw(text), unicodeByDefault || isUnicode(text)));
}
myDecodedFragments = result;
}
@@ -190,6 +203,7 @@
// TODO: Implement unicode character name escapes: EscapeRegexGroup.UNICODE_NAMED
final String unicode16 = escapeRegexGroup(escMatcher, EscapeRegexGroup.UNICODE_16BIT);
final String unicode32 = escapeRegexGroup(escMatcher, EscapeRegexGroup.UNICODE_32BIT);
+ final String wholeMatch = escapeRegexGroup(escMatcher, EscapeRegexGroup.WHOLE_MATCH);
final boolean escapedUnicode = raw && unicode || !raw;
@@ -201,13 +215,13 @@
str = new String(new char[]{(char)Integer.parseInt(hex, 16)});
}
else if (escapedUnicode && unicode16 != null) {
- str = unicode ? new String(new char[]{(char)Integer.parseInt(unicode16, 16)}) : unicode16;
+ str = unicode ? new String(new char[]{(char)Integer.parseInt(unicode16, 16)}) : wholeMatch;
}
else if (escapedUnicode && unicode32 != null) {
- str = unicode ? new String(Character.toChars((int)Long.parseLong(unicode32, 16))) : unicode32;
+ str = unicode ? new String(Character.toChars((int)Long.parseLong(unicode32, 16))) : wholeMatch;
}
else if (raw) {
- str = escapeRegexGroup(escMatcher, EscapeRegexGroup.WHOLE_MATCH);
+ str = wholeMatch;
}
else {
final String toReplace = escapeRegexGroup(escMatcher, EscapeRegexGroup.ESCAPED_SUBSTRING);
@@ -215,8 +229,8 @@
}
if (str != null) {
- final TextRange wholeMatch = TextRange.create(escMatcher.start(), escMatcher.end());
- result.add(Pair.create(wholeMatch.shiftRight(offset), str));
+ final TextRange wholeMatchRange = TextRange.create(escMatcher.start(), escMatcher.end());
+ result.add(Pair.create(wholeMatchRange.shiftRight(offset), str));
}
index = escMatcher.end();
diff --git a/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java
index c19e9ad..6143828 100644
--- a/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java
@@ -19,6 +19,7 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.PsiReference;
+import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDialectsTokenSetProvider;
@@ -37,10 +38,21 @@
super(astNode);
}
+ @NotNull
public PyExpression getOperand() {
return childToPsiNotNull(PythonDialectsTokenSetProvider.INSTANCE.getExpressionTokens(), 0);
}
+ @NotNull
+ @Override
+ public PyExpression getRootOperand() {
+ PyExpression operand = getOperand();
+ while (operand instanceof PySubscriptionExpression) {
+ operand = ((PySubscriptionExpression)operand).getOperand();
+ }
+ return operand;
+ }
+
@Nullable
public PyExpression getIndexExpression() {
return childToPsi(PythonDialectsTokenSetProvider.INSTANCE.getExpressionTokens(), 1);
@@ -74,7 +86,7 @@
res = ((PySubscriptableType)type).getElementType(indexExpression, context);
}
else if (type instanceof PyCollectionType) {
- res = ((PyCollectionType) type).getElementType(context);
+ res = ((PyCollectionType)type).getElementType(context);
}
}
}
@@ -96,6 +108,17 @@
return getOperand();
}
+ @Nullable
+ @Override
+ public QualifiedName asQualifiedName() {
+ return PyPsiUtils.asQualifiedName(this);
+ }
+
+ @Override
+ public boolean isQualified() {
+ return getQualifier() != null;
+ }
+
@Override
public String getReferencedName() {
String res = PyNames.GETITEM;
diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
index ae2e30f..c56111e 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
@@ -60,6 +60,8 @@
* @author yole
*/
public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExpressionStub> implements PyTargetExpression {
+ QualifiedName myQualifiedName;
+
public PyTargetExpressionImpl(ASTNode astNode) {
super(astNode);
}
@@ -356,7 +358,7 @@
}
if (source != null) {
final PyType sourceType = context.getType(source);
- final PyType type = getIterationType(sourceType, source, context);
+ final PyType type = getIterationType(sourceType, source, this, context);
if (type instanceof PyTupleType && target instanceof PyTupleExpression) {
return getTypeFromTupleAssignment((PyTupleExpression)target, (PyTupleType)type);
}
@@ -368,7 +370,8 @@
}
@Nullable
- private static PyType getIterationType(@Nullable PyType iterableType, @Nullable PyExpression source, @NotNull TypeEvalContext context) {
+ private static PyType getIterationType(@Nullable PyType iterableType, @Nullable PyExpression source, @NotNull PsiElement anchor,
+ @NotNull TypeEvalContext context) {
PyType result = null;
if (iterableType instanceof PyCollectionType) {
result = ((PyCollectionType)iterableType).getElementType(context);
@@ -386,43 +389,32 @@
final Collection<PyType> members = ((PyUnionType)iterableType).getMembers();
final List<PyType> iterationTypes = new ArrayList<PyType>();
for (PyType member : members) {
- iterationTypes.add(getIterationType(member, source, context));
+ iterationTypes.add(getIterationType(member, source, anchor, context));
}
return PyUnionType.union(iterationTypes);
}
- else if (iterableType instanceof PyClassType) {
- final PyClass pyClass = ((PyClassType)iterableType).getPyClass();
- for (PyTypeProvider provider: Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
- final PyType iterationType = provider.getIterationType(pyClass);
- if (iterationType != null) {
- result = iterationType;
- break;
+ else if (iterableType != null && PyABCUtil.isSubtype(iterableType, PyNames.ITERATOR, context)) {
+ final PyFunction iterateMethod = findMethodByName(iterableType, PyNames.ITER, context);
+ PyType iterateMethodType = null;
+ if (iterateMethod != null) {
+ iterateMethodType = getContextSensitiveType(iterateMethod, context, source);
+ }
+ if (iterateMethodType instanceof PyCollectionType) {
+ final PyCollectionType collectionType = (PyCollectionType)iterateMethodType;
+ result = collectionType.getElementType(context);
+ }
+ if (result == null) {
+ final String nextMethodName = LanguageLevel.forElement(anchor).isAtLeast(LanguageLevel.PYTHON30) ?
+ PyNames.DUNDER_NEXT : PyNames.NEXT;
+ final PyFunction next = findMethodByName(iterableType, nextMethodName, context);
+ if (next != null) {
+ result = getContextSensitiveType(next, context, source);
}
}
- if (PyABCUtil.isSubclass(pyClass, PyNames.ITERATOR)) {
- final PyFunction iterateMethod = pyClass.findMethodByName(PyNames.ITER, true);
- PyType iterateMethodType = null;
- if (iterateMethod != null) {
- iterateMethodType = getContextSensitiveType(iterateMethod, context, source);
- }
- if (iterateMethodType instanceof PyCollectionType) {
- final PyCollectionType collectionType = (PyCollectionType)iterateMethodType;
- result = collectionType.getElementType(context);
- }
- if (result == null) {
- PyFunction next = pyClass.findMethodByName(PyNames.NEXT, true);
- if (next == null) {
- next = pyClass.findMethodByName(PyNames.DUNDER_NEXT, true);
- }
- if (next != null) {
- result = getContextSensitiveType(next, context, source);
- }
- }
- if (result == null) {
- final PyFunction getItem = pyClass.findMethodByName(PyNames.GETITEM, true);
- if (getItem != null) {
- result = getContextSensitiveType(getItem, context, source);
- }
+ if (result == null) {
+ final PyFunction getItem = findMethodByName(iterableType, PyNames.GETITEM, context);
+ if (getItem != null) {
+ result = getContextSensitiveType(getItem, context, source);
}
}
}
@@ -430,6 +422,20 @@
}
@Nullable
+ private static PyFunction findMethodByName(@NotNull PyType type, @NotNull String name, @NotNull TypeEvalContext context) {
+ final PyResolveContext resolveContext = PyResolveContext.defaultContext().withTypeEvalContext(context);
+ final List<? extends RatedResolveResult> results = type.resolveMember(name, null, AccessDirection.READ, resolveContext);
+ if (results != null && !results.isEmpty()) {
+ final RatedResolveResult result = results.get(0);
+ final PsiElement element = result.getElement();
+ if (element instanceof PyFunction) {
+ return (PyFunction)element;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
private static PyType getContextSensitiveType(@NotNull PyFunction function, @NotNull TypeEvalContext context,
@Nullable PyExpression source) {
if (function instanceof PyFunctionImpl) {
@@ -459,6 +465,15 @@
return qualifier != null ? (PyExpression) qualifier.getPsi() : null;
}
+ @Nullable
+ @Override
+ public QualifiedName asQualifiedName() {
+ if (myQualifiedName == null) {
+ myQualifiedName = PyPsiUtils.asQualifiedName(this);
+ }
+ return myQualifiedName;
+ }
+
public String toString() {
return super.toString() + ": " + getName();
}
@@ -501,7 +516,7 @@
}
return null;
}
- return PyQualifiedNameFactory.fromExpression(findAssignedValue());
+ return PyPsiUtils.asQualifiedName(findAssignedValue());
}
@Nullable
@@ -552,7 +567,7 @@
final PyExpression value = findAssignedValue();
if (value instanceof PyCallExpression) {
final PyExpression callee = ((PyCallExpression)value).getCallee();
- return PyQualifiedNameFactory.fromExpression(callee);
+ return PyPsiUtils.asQualifiedName(callee);
}
return null;
}
@@ -565,7 +580,7 @@
@NotNull
public PsiPolyVariantReference getReference(final PyResolveContext resolveContext) {
- if (getQualifier() != null) {
+ if (isQualified()) {
return new PyQualifiedReference(this, resolveContext);
}
return new PyTargetReference(this, resolveContext);
@@ -574,6 +589,9 @@
@NotNull
@Override
public SearchScope getUseScope() {
+ if (isQualified()) {
+ return super.getUseScope();
+ }
final ScopeOwner owner = ScopeUtil.getScopeOwner(this);
if (owner != null) {
final Scope scope = ControlFlowCache.getScope(owner);
@@ -590,7 +608,7 @@
while(true) {
PyElement parentContainer = PsiTreeUtil.getParentOfType(container, PyFunction.class, PyClass.class);
if (parentContainer instanceof PyClass) {
- if (getQualifier() != null) {
+ if (isQualified()) {
return super.getUseScope();
}
break;
@@ -677,4 +695,10 @@
}
return null;
}
+
+ @Override
+ public void subtreeChanged() {
+ super.subtreeChanged();
+ myQualifiedName = null;
+ }
}
diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyFromImportSourceReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyFromImportSourceReference.java
index 61ffb43..8cba7fb 100644
--- a/python/src/com/jetbrains/python/psi/impl/references/PyFromImportSourceReference.java
+++ b/python/src/com/jetbrains/python/psi/impl/references/PyFromImportSourceReference.java
@@ -18,7 +18,6 @@
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
-import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyFromImportStatement;
import com.jetbrains.python.psi.impl.PyReferenceExpressionImpl;
import com.jetbrains.python.psi.resolve.PyResolveContext;
@@ -53,7 +52,6 @@
@Override
public HighlightSeverity getUnresolvedHighlightSeverity(TypeEvalContext context) {
- PyExpression qualifier = myElement.getQualifier();
- return qualifier == null ? HighlightSeverity.ERROR : HighlightSeverity.WARNING;
+ return myElement.isQualified() ? HighlightSeverity.WARNING : HighlightSeverity.ERROR;
}
}
diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java
index 750c20f..e66a219 100644
--- a/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java
+++ b/python/src/com/jetbrains/python/psi/impl/references/PyQualifiedReference.java
@@ -35,9 +35,14 @@
import com.intellij.util.ProcessingContext;
import com.intellij.util.indexing.FileBasedIndex;
import com.jetbrains.python.PyNames;
+import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
+import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
-import com.jetbrains.python.psi.impl.*;
+import com.jetbrains.python.psi.impl.PyBuiltinCache;
+import com.jetbrains.python.psi.impl.PyImportedModule;
+import com.jetbrains.python.psi.impl.ResolveResultList;
import com.jetbrains.python.psi.resolve.*;
import com.jetbrains.python.psi.search.PyProjectScopeBuilder;
import com.jetbrains.python.psi.stubs.PyClassNameIndexInsensitive;
@@ -372,15 +377,28 @@
}
private static Collection<PyExpression> collectAssignedAttributes(PyQualifiedExpression qualifier) {
- QualifiedName qualifierPath = PyQualifiedNameFactory.fromReferenceChain(PyResolveUtil.unwindQualifiers(qualifier));
- if (qualifierPath != null) {
- AssignmentCollectProcessor proc = new AssignmentCollectProcessor(qualifierPath);
- PyResolveUtil.treeCrawlUp(proc, qualifier);
- return proc.getResult();
+ final Set<String> names = new HashSet<String>();
+ final QualifiedName qualifierQName = qualifier.asQualifiedName();
+ if (qualifierQName != null) {
+ final List<PyExpression> results = new ArrayList<PyExpression>();
+ for (ScopeOwner owner = ScopeUtil.getScopeOwner(qualifier); owner != null; owner = ScopeUtil.getScopeOwner(owner)) {
+ final Scope scope = ControlFlowCache.getScope(owner);
+ for (PyTargetExpression target : scope.getTargetExpressions()) {
+ final QualifiedName targetQName = target.asQualifiedName();
+ if (targetQName != null) {
+ if (targetQName.getComponentCount() == qualifierQName.getComponentCount() + 1 && targetQName.matchesPrefix(qualifierQName)) {
+ final String name = target.getName();
+ if (!names.contains(name)) {
+ names.add(name);
+ results.add(target);
+ }
+ }
+ }
+ }
+ }
+ return results;
}
- else {
- return Collections.emptyList();
- }
+ return Collections.emptyList();
}
@Override
@@ -468,8 +486,8 @@
return true;
}
if (element instanceof PyTargetExpression) {
- return ((PyTargetExpression)element).getQualifier() == null &&
- PsiTreeUtil.getParentOfType(element, ScopeOwner.class) instanceof PyFunction;
+ final PyTargetExpression target = (PyTargetExpression)element;
+ return !target.isQualified() && ScopeUtil.getScopeOwner(target) instanceof PyFunction;
}
return false;
}
diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java
index 6a1b116..df4fb34 100644
--- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java
@@ -550,10 +550,10 @@
}
private boolean haveQualifiers(PsiElement element) {
- if (myElement.getQualifier() != null) {
+ if (myElement.isQualified()) {
return true;
}
- if (element instanceof PyQualifiedExpression && ((PyQualifiedExpression)element).getQualifier() != null) {
+ if (element instanceof PyQualifiedExpression && ((PyQualifiedExpression)element).isQualified()) {
return true;
}
return false;
diff --git a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java
index 813fb5c..e3d399c 100644
--- a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java
+++ b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java
@@ -24,7 +24,6 @@
import com.jetbrains.python.psi.impl.PyClassImpl;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.intellij.psi.util.QualifiedName;
-import com.jetbrains.python.psi.impl.PyQualifiedNameFactory;
import com.jetbrains.python.psi.stubs.PyClassNameIndex;
import com.jetbrains.python.psi.stubs.PyClassNameIndexInsensitive;
import com.jetbrains.python.psi.stubs.PyClassStub;
@@ -59,12 +58,16 @@
final PyExpression[] exprs = psi.getSuperClassExpressions();
List<QualifiedName> superClasses = new ArrayList<QualifiedName>();
for (PyExpression expression : exprs) {
+ if (expression instanceof PyKeywordArgument) {
+ continue;
+ }
expression = PyClassImpl.unfoldClass(expression);
- superClasses.add(PyQualifiedNameFactory.fromExpression(expression));
+ superClasses.add(PyPsiUtils.asQualifiedName(expression));
}
final PyStringLiteralExpression docStringExpression = psi.getDocStringExpression();
return new PyClassStubImpl(psi.getName(), parentStub,
superClasses.toArray(new QualifiedName[superClasses.size()]),
+ PyPsiUtils.asQualifiedName(psi.getMetaClassExpression()),
psi.getOwnSlots(),
PyPsiUtils.strValue(docStringExpression),
getStubElementType());
@@ -77,6 +80,7 @@
for (QualifiedName s : classes) {
QualifiedName.serialize(s, dataStream);
}
+ QualifiedName.serialize(pyClassStub.getMetaClass(), dataStream);
PyFileElementType.writeNullableList(dataStream, pyClassStub.getSlots());
final String docString = pyClassStub.getDocString();
dataStream.writeUTFFast(docString != null ? docString : "");
@@ -90,9 +94,11 @@
for (int i = 0; i < superClassCount; i++) {
superClasses[i] = QualifiedName.deserialize(dataStream);
}
+ final QualifiedName metaClass = QualifiedName.deserialize(dataStream);
List<String> slots = PyFileElementType.readNullableList(dataStream);
final String docString = dataStream.readUTFFast();
- return new PyClassStubImpl(name, parentStub, superClasses, slots, docString.length() > 0 ? docString : null, getStubElementType());
+ return new PyClassStubImpl(name, parentStub, superClasses, metaClass, slots, docString.length() > 0 ? docString : null,
+ getStubElementType());
}
public void indexStub(@NotNull final PyClassStub stub, @NotNull final IndexSink sink) {
diff --git a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassStubImpl.java b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassStubImpl.java
index e607478..0de9181 100644
--- a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassStubImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassStubImpl.java
@@ -21,6 +21,7 @@
import com.jetbrains.python.psi.PyClass;
import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.psi.stubs.PyClassStub;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -30,14 +31,16 @@
public class PyClassStubImpl extends StubBase<PyClass> implements PyClassStub {
private final String myName;
private final QualifiedName[] mySuperClasses;
+ @Nullable private final QualifiedName myMetaClass;
private final List<String> mySlots;
private final String myDocString;
- public PyClassStubImpl(final String name, StubElement parentStub, final QualifiedName[] superClasses, final List<String> slots,
- String docString, IStubElementType stubElementType) {
+ public PyClassStubImpl(final String name, StubElement parentStub, final QualifiedName[] superClasses, @Nullable QualifiedName metaClass,
+ final List<String> slots, String docString, IStubElementType stubElementType) {
super(parentStub, stubElementType);
myName = name;
mySuperClasses = superClasses;
+ myMetaClass = metaClass;
mySlots = slots;
myDocString = docString;
}
@@ -50,6 +53,12 @@
return mySuperClasses;
}
+ @Nullable
+ @Override
+ public QualifiedName getMetaClass() {
+ return myMetaClass;
+ }
+
@Override
public List<String> getSlots() {
return mySlots;
diff --git a/python/src/com/jetbrains/python/psi/impl/stubs/PyTargetExpressionElementType.java b/python/src/com/jetbrains/python/psi/impl/stubs/PyTargetExpressionElementType.java
index f2a0678..aa535e8 100644
--- a/python/src/com/jetbrains/python/psi/impl/stubs/PyTargetExpressionElementType.java
+++ b/python/src/com/jetbrains/python/psi/impl/stubs/PyTargetExpressionElementType.java
@@ -85,7 +85,7 @@
initializer = ((PyReferenceExpression) callee).asQualifiedName();
}
}
- return new PyTargetExpressionStubImpl(name, docString, initializerType, initializer, psi.getQualifier() != null, parentStub);
+ return new PyTargetExpressionStubImpl(name, docString, initializerType, initializer, psi.isQualified(), parentStub);
}
public void serialize(@NotNull final PyTargetExpressionStub stub, @NotNull final StubOutputStream stream)
diff --git a/python/src/com/jetbrains/python/psi/resolve/AssignmentCollectProcessor.java b/python/src/com/jetbrains/python/psi/resolve/AssignmentCollectProcessor.java
index 0dde395..1f02473 100644
--- a/python/src/com/jetbrains/python/psi/resolve/AssignmentCollectProcessor.java
+++ b/python/src/com/jetbrains/python/psi/resolve/AssignmentCollectProcessor.java
@@ -19,11 +19,10 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.ResolveState;
import com.intellij.psi.scope.PsiScopeProcessor;
+import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.psi.PyAssignmentStatement;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyTargetExpression;
-import com.intellij.psi.util.QualifiedName;
-import com.jetbrains.python.psi.impl.PyQualifiedNameFactory;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@@ -56,15 +55,12 @@
for (PyExpression ex : assignment.getTargets()) {
if (ex instanceof PyTargetExpression) {
final PyTargetExpression target = (PyTargetExpression)ex;
- List<PyExpression> qualsExpr = PyResolveUtil.unwindQualifiers(target);
- QualifiedName qualifiedName = PyQualifiedNameFactory.fromReferenceChain(qualsExpr);
+ final QualifiedName qualifiedName = target.asQualifiedName();
if (qualifiedName != null) {
if (qualifiedName.getComponentCount() == myQualifier.getComponentCount() + 1 && qualifiedName.matchesPrefix(myQualifier)) {
- // a new attribute follows last qualifier; collect it.
- PyExpression last_elt = qualsExpr.get(qualsExpr.size() - 1); // last item is the outermost, new, attribute.
- String last_elt_name = last_elt.getName();
+ String last_elt_name = target.getName();
if (!mySeenNames.contains(last_elt_name)) { // no dupes, only remember the latest
- myResult.add(last_elt);
+ myResult.add(target);
mySeenNames.add(last_elt_name);
}
}
diff --git a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java
index 9646170..da8c0d6 100644
--- a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java
+++ b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java
@@ -35,14 +35,9 @@
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyPsiUtils;
-import com.intellij.psi.util.QualifiedName;
-import com.jetbrains.python.psi.impl.PyQualifiedNameFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.LinkedList;
-import java.util.List;
-
/**
* Ref resolution routines.
* User: dcheryasov
@@ -62,7 +57,7 @@
* @return previous statement, or null.
*/
@Nullable
- public static PsiElement getPrevNodeOf(PsiElement elt, TokenSet elementTypes) {
+ private static PsiElement getPrevNodeOf(PsiElement elt, TokenSet elementTypes) {
ASTNode seeker = elt.getNode();
while (seeker != null) {
ASTNode feeler = seeker.getTreePrev();
@@ -89,7 +84,7 @@
}
@Nullable
- public static PsiElement getPrevNodeOf(PsiElement elt) {
+ private static PsiElement getPrevNodeOf(PsiElement elt) {
if (elt instanceof PsiFile) return null; // no sense to get the previous node of a file
return getPrevNodeOf(elt, PythonDialectsTokenSetProvider.INSTANCE.getNameDefinerTokens());
}
@@ -164,7 +159,10 @@
* @param processor a visitor that says when the crawl is done and collects info.
* @param elt element from which we start (not checked by processor); if null, the search immediately returns null.
* @return first element that the processor accepted.
+ *
+ * @deprecated Use {@link #scopeCrawlUp} instead.
*/
+ @Deprecated
@Nullable
public static PsiElement treeCrawlUp(PsiScopeProcessor processor, PsiElement elt) {
if (elt == null || !elt.isValid()) return null; // can't find anyway.
@@ -231,7 +229,7 @@
* @return true if an outer element is in a class context, while the inner is a method or function inside it.
* @see com.jetbrains.python.psi.PyUtil#getConcealingParent(com.intellij.psi.PsiElement)
*/
- protected static boolean refersFromMethodToClass(final PyFunction innerFunction, final PsiElement outer) {
+ private static boolean refersFromMethodToClass(final PyFunction innerFunction, final PsiElement outer) {
if (innerFunction == null) {
return false;
}
@@ -244,49 +242,6 @@
}
/**
- * Unwinds a multi-level qualified expression into a path, as seen in source text, i.e. outermost qualifier first.
- *
- * @param expr an expression to unwind.
- * @return path as a list of ref expressions.
- */
- @NotNull
- public static List<PyExpression> unwindQualifiers(@NotNull final PyQualifiedExpression expr) {
- final List<PyExpression> path = new LinkedList<PyExpression>();
- PyQualifiedExpression e = expr;
- while (e != null) {
- path.add(0, e);
- final PyExpression q = e.getQualifier();
- e = q instanceof PyQualifiedExpression ? (PyQualifiedExpression)q : null;
- }
- return path;
- }
-
- public static List<String> unwindQualifiersAsStrList(final PyQualifiedExpression expr) {
- final List<String> path = new LinkedList<String>();
- PyQualifiedExpression e = expr;
- while (e != null) {
- path.add(0, e.getText());
- final PyExpression q = e.getQualifier();
- e = q instanceof PyQualifiedExpression ? (PyQualifiedExpression)q : null;
- }
- return path;
- }
-
- public static String toPath(PyQualifiedExpression expr) {
- if (expr == null) return "";
- List<PyExpression> path = unwindQualifiers(expr);
- final QualifiedName qName = PyQualifiedNameFactory.fromReferenceChain(path);
- if (qName != null) {
- return qName.toString();
- }
- String name = expr.getName();
- if (name != null) {
- return name;
- }
- return "";
- }
-
- /**
* Accepts only targets that are not the given object.
*/
public static class FilterNotInstance implements Condition<PsiElement> {
diff --git a/python/src/com/jetbrains/python/psi/search/PyKeywordArgumentSearchExecutor.java b/python/src/com/jetbrains/python/psi/search/PyKeywordArgumentSearchExecutor.java
index f8becd8d..1b4fd6a 100644
--- a/python/src/com/jetbrains/python/psi/search/PyKeywordArgumentSearchExecutor.java
+++ b/python/src/com/jetbrains/python/psi/search/PyKeywordArgumentSearchExecutor.java
@@ -21,6 +21,8 @@
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Processor;
+import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
+import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
@@ -34,8 +36,8 @@
if (!(element instanceof PyNamedParameter)) {
return;
}
- PyFunction owner = PsiTreeUtil.getParentOfType(element, PyFunction.class);
- if (owner == null) {
+ final ScopeOwner owner = ScopeUtil.getScopeOwner(element);
+ if (!(owner instanceof PyFunction)) {
return;
}
ReferencesSearch.search(owner, queryParameters.getScope()).forEach(new Processor<PsiReference>() {
diff --git a/python/src/com/jetbrains/python/psi/search/PyStringReferenceSearch.java b/python/src/com/jetbrains/python/psi/search/PyStringReferenceSearch.java
index fa92691..dabd591 100644
--- a/python/src/com/jetbrains/python/psi/search/PyStringReferenceSearch.java
+++ b/python/src/com/jetbrains/python/psi/search/PyStringReferenceSearch.java
@@ -15,8 +15,6 @@
*/
package com.jetbrains.python.psi.search;
-import com.intellij.openapi.application.AccessToken;
-import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.QueryExecutorBase;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDirectory;
@@ -36,6 +34,11 @@
* @author traff
*/
public class PyStringReferenceSearch extends QueryExecutorBase<PsiReference, ReferencesSearch.SearchParameters> {
+
+ public PyStringReferenceSearch() {
+ super(true);
+ }
+
public void processQuery(@NotNull final ReferencesSearch.SearchParameters params,
@NotNull final Processor<PsiReference> consumer) {
final PsiElement element = params.getElementToSearch();
@@ -43,20 +46,12 @@
return;
}
- AccessToken token = ApplicationManager.getApplication().acquireReadActionLock();
- String name;
- SearchScope searchScope;
- try {
- searchScope = params.getEffectiveSearchScope();
- if (searchScope instanceof GlobalSearchScope) {
- searchScope = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope)searchScope, PythonFileType.INSTANCE);
- }
+ SearchScope searchScope = params.getEffectiveSearchScope();
+ if (searchScope instanceof GlobalSearchScope) {
+ searchScope = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope)searchScope, PythonFileType.INSTANCE);
+ }
- name = PyUtil.computeElementNameForStringSearch(element);
- }
- finally {
- token.finish();
- }
+ String name = PyUtil.computeElementNameForStringSearch(element);
if (StringUtil.isEmpty(name)) {
return;
diff --git a/python/src/com/jetbrains/python/psi/types/PyABCUtil.java b/python/src/com/jetbrains/python/psi/types/PyABCUtil.java
index faf10ba..fcd3289 100644
--- a/python/src/com/jetbrains/python/psi/types/PyABCUtil.java
+++ b/python/src/com/jetbrains/python/psi/types/PyABCUtil.java
@@ -83,16 +83,26 @@
return false;
}
- public static boolean isSubtype(@NotNull PyType type, @NotNull String superClassName) {
+ public static boolean isSubtype(@NotNull PyType type, @NotNull String superClassName, @NotNull TypeEvalContext context) {
if (type instanceof PyClassType) {
- final PyClass pyClass = ((PyClassType)type).getPyClass();
- return isSubclass(pyClass, superClassName, true);
+ final PyClassType classType = (PyClassType)type;
+ final PyClass pyClass = classType.getPyClass();
+ if (classType.isDefinition()) {
+ final PyClassLikeType metaClassType = classType.getMetaClassType(context, true);
+ if (metaClassType instanceof PyClassType) {
+ final PyClassType metaClass = (PyClassType)metaClassType;
+ return isSubclass(metaClass.getPyClass(), superClassName, true);
+ }
+ }
+ else {
+ return isSubclass(pyClass, superClassName, true);
+ }
}
if (type instanceof PyUnionType) {
final PyUnionType unionType = (PyUnionType)type;
for (PyType m : unionType.getMembers()) {
if (m != null) {
- if (!isSubtype(m, superClassName)) {
+ if (!isSubtype(m, superClassName, context)) {
return false;
}
}
diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java
index e475429..10c06f5 100644
--- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java
+++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java
@@ -209,7 +209,7 @@
}
if (isDefinition() && myClass.isNewStyleClass()) {
- PyClassType typeType = getMetaclassType();
+ final PyClassLikeType typeType = getMetaClassType(context, inherited);
if (typeType != null) {
List<? extends RatedResolveResult> typeMembers = typeType.resolveMember(name, location, direction, resolveContext);
if (typeMembers != null && !typeMembers.isEmpty()) {
@@ -265,12 +265,24 @@
}
@Nullable
- private PyClassType getMetaclassType() {
- final PyClass metaClass = PyUtil.getMetaClass(myClass);
- if (metaClass != null) {
- return new PyClassTypeImpl(metaClass, false);
+ @Override
+ public PyClassLikeType getMetaClassType(@NotNull TypeEvalContext context, boolean inherited) {
+ final PyClassLikeType ownMeta = myClass.getMetaClassType(context);
+ if (ownMeta != null) {
+ return ownMeta;
}
- return PyBuiltinCache.getInstance(myClass).getObjectType("type");
+ if (inherited) {
+ for (PyClassLikeType ancestor : myClass.getAncestorTypes(context)) {
+ if (ancestor != null) {
+ final PyClassLikeType ancestorMeta = ancestor.getMetaClassType(context, false);
+ if (ancestorMeta != null) {
+ return ancestorMeta;
+ }
+ }
+ }
+ return PyBuiltinCache.getInstance(myClass).getObjectType("type");
+ }
+ return null;
}
@Override
@@ -419,7 +431,7 @@
}
if (isDefinition() && myClass.isNewStyleClass()) {
- final PyClassType typeType = getMetaclassType();
+ final PyClassLikeType typeType = getMetaClassType(typeEvalContext, true);
if (typeType != null) {
Collections.addAll(ret, typeType.getCompletionVariants(prefix, location, context));
}
diff --git a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java
index e17c76c..7f77401 100644
--- a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java
@@ -104,7 +104,7 @@
}
int offset = editor.getCaretModel().getOffset();
for (PsiElement occurrence : occurrences) {
- if (occurrence.getTextRange().contains(offset)) {
+ if (occurrence != null && occurrence.getTextRange().contains(offset)) {
return occurrence;
}
}
diff --git a/python/src/com/jetbrains/python/refactoring/introduce/field/PyIntroduceFieldHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/field/PyIntroduceFieldHandler.java
index 3818370e..6cdc4b3 100644
--- a/python/src/com/jetbrains/python/refactoring/introduce/field/PyIntroduceFieldHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/introduce/field/PyIntroduceFieldHandler.java
@@ -310,7 +310,7 @@
private static void putCaretOnFieldName(Editor editor, PsiElement occurrence) {
PyQualifiedExpression qExpr = PsiTreeUtil.getParentOfType(occurrence, PyQualifiedExpression.class, false);
- if (qExpr != null && qExpr.getQualifier() == null) {
+ if (qExpr != null && !qExpr.isQualified()) {
qExpr = PsiTreeUtil.getParentOfType(qExpr, PyQualifiedExpression.class);
}
if (qExpr != null) {
diff --git a/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionProcessor.java b/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionProcessor.java
index 5c22514..21c2604 100644
--- a/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionProcessor.java
+++ b/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionProcessor.java
@@ -183,7 +183,7 @@
if (oldElement instanceof PyClass && PyNames.INIT.equals(expr.getName())) {
return;
}
- if (expr.getQualifier() != null) {
+ if (expr.isQualified()) {
final PyElementGenerator generator = PyElementGenerator.getInstance(expr.getProject());
final PyExpression generated = generator.createExpressionFromText(LanguageLevel.forElement(expr), expr.getName());
final PsiElement newExpr = expr.replace(generated);
diff --git a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java
index 84164cb..901aeee 100644
--- a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java
@@ -109,7 +109,7 @@
}
else if (element instanceof PyReferenceExpression) {
updatedFiles.add(file);
- if (((PyReferenceExpression)element).getQualifier() != null) {
+ if (((PyReferenceExpression)element).isQualified()) {
final QualifiedName newQualifiedName = QualifiedNameFinder.findCanonicalImportPath(newElement, element);
replaceWithQualifiedExpression(element, newQualifiedName);
} else {
diff --git a/python/src/com/jetbrains/python/run/PythonRunConfigurationProducer.java b/python/src/com/jetbrains/python/run/PythonRunConfigurationProducer.java
index c14bde2..5817768 100644
--- a/python/src/com/jetbrains/python/run/PythonRunConfigurationProducer.java
+++ b/python/src/com/jetbrains/python/run/PythonRunConfigurationProducer.java
@@ -17,6 +17,7 @@
import com.intellij.execution.Location;
import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
import com.intellij.execution.actions.RunConfigurationProducer;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
@@ -94,4 +95,8 @@
}
return true;
}
+ @Override
+ public boolean isPreferredConfiguration(ConfigurationFromContext self, ConfigurationFromContext other) {
+ return other.isProducedBy(PythonRunConfigurationProducer.class);
+ }
}
diff --git a/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java b/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
index 1f58a73..fd043ce5 100644
--- a/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
+++ b/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
@@ -220,7 +220,7 @@
if (element instanceof PyClass || element instanceof PyFunction) {
return true;
}
- if (!(parent instanceof PyClass) && (element instanceof PyTargetExpression) && ((PyTargetExpression)element).getQualifier() == null) {
+ if (!(parent instanceof PyClass) && (element instanceof PyTargetExpression) && !((PyTargetExpression)element).isQualified()) {
PsiElement e = element.getParent();
if (e instanceof PyAssignmentStatement) {
e = e.getParent();
diff --git a/python/src/com/jetbrains/python/testing/TestRunnerService.java b/python/src/com/jetbrains/python/testing/TestRunnerService.java
index 32bcc26..3301909 100644
--- a/python/src/com/jetbrains/python/testing/TestRunnerService.java
+++ b/python/src/com/jetbrains/python/testing/TestRunnerService.java
@@ -34,7 +34,7 @@
)
public class TestRunnerService implements PersistentStateComponent<TestRunnerService> {
private List<String> myConfigurations = new ArrayList<String>();
- public String PROJECT_TEST_RUNNER = "";
+ public String PROJECT_TEST_RUNNER = PythonTestConfigurationsModel.PYTHONS_UNITTEST_NAME;
public TestRunnerService() {
myConfigurations.add(PythonTestConfigurationsModel.PYTHONS_UNITTEST_NAME);
diff --git a/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestConfigurationProducer.java b/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestConfigurationProducer.java
index 5cf9784..b7dc704 100644
--- a/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestConfigurationProducer.java
+++ b/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestConfigurationProducer.java
@@ -47,6 +47,6 @@
@Override
protected boolean isTestFunction(@NotNull final PyFunction pyFunction, @Nullable final AbstractPythonTestRunConfiguration configuration) {
- return PythonUnitTestUtil.isTestCaseFunction(pyFunction, false);
+ return PythonUnitTestUtil.isTestCaseFunction(pyFunction, true);
}
}
\ No newline at end of file
diff --git a/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestUrlProvider.java b/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestUrlProvider.java
index 684a09b..2c7787c 100644
--- a/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestUrlProvider.java
+++ b/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestUrlProvider.java
@@ -43,11 +43,14 @@
}
final int listSize = list.size();
- // parse path as [ns.]*fileName.className[.methodName]
+ // parse path as [ns.]*fileName[.className][.methodName]
if (listSize == 2) {
final List<Location> classes = PythonUnitTestUtil.findLocations(project, list.get(0), list.get(1), null);
if (classes.size() > 0)
return classes;
+ final List<Location> functions = PythonUnitTestUtil.findLocations(project, list.get(0), null, list.get(1));
+ if (functions.size() > 0)
+ return functions;
}
if (listSize > 2) {
diff --git a/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java b/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java
index 728a6e1..cc6d445 100644
--- a/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java
+++ b/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java
@@ -37,7 +37,7 @@
@Override
public void visitPyReferenceExpression(PyReferenceExpression node) {
final String referencedName = node.getReferencedName();
- if (node.getQualifier() == null && referencedName != null) {
+ if (!node.isQualified() && referencedName != null) {
PyFunction function = PsiTreeUtil.getParentOfType(node, PyFunction.class);
if (function != null) {
final PyNamedParameter element = function.getParameterList().findParameterByName(referencedName);
diff --git a/python/src/com/jetbrains/python/validation/PyBuiltinAnnotator.java b/python/src/com/jetbrains/python/validation/PyBuiltinAnnotator.java
index 7e69319..417c362 100644
--- a/python/src/com/jetbrains/python/validation/PyBuiltinAnnotator.java
+++ b/python/src/com/jetbrains/python/validation/PyBuiltinAnnotator.java
@@ -36,7 +36,7 @@
final String name = node.getName();
if (name == null) return;
boolean highlighted_as_attribute = highlightAsAttribute(node, name);
- if (! highlighted_as_attribute && node.getQualifier() == null) {
+ if (! highlighted_as_attribute && !node.isQualified()) {
// things like len()
ResolveResult[] resolved = node.getReference().multiResolve(false); // constructors, etc may give multiple results...
if (resolved.length > 0) {
@@ -71,7 +71,7 @@
if (PyNames.UnderscoredAttributes.contains(name) || PyNames.getBuiltinMethods(languageLevel).containsKey(name)) {
// things like __len__
if (
- (node.getQualifier() != null) // foo.__len__
+ node.isQualified() // foo.__len__
|| (PyUtil.getConcealingParent(node) instanceof PyClass) // class Foo: ... __len__ = myLenImpl
) {
final ASTNode astNode = node.getNode();
diff --git a/python/testData/addImport/comment.after.py b/python/testData/addImport/comment.after.py
index 777f480..a816490 100644
--- a/python/testData/addImport/comment.after.py
+++ b/python/testData/addImport/comment.after.py
@@ -1 +1 @@
-from urllib import urlopen, urlencode, unquote_plus # this is a comment
\ No newline at end of file
+from urllib import urlopen, urlencode, unquote_plus # this is a comment
\ No newline at end of file
diff --git a/python/testData/formatter/alignInCallExpression.py b/python/testData/formatter/alignInCallExpression.py
new file mode 100644
index 0000000..0c1dff1
--- /dev/null
+++ b/python/testData/formatter/alignInCallExpression.py
@@ -0,0 +1,3 @@
+foo(1 +
+ x.
+ call())
\ No newline at end of file
diff --git a/python/testData/formatter/alignInCallExpression_after.py b/python/testData/formatter/alignInCallExpression_after.py
new file mode 100644
index 0000000..48c17a1
--- /dev/null
+++ b/python/testData/formatter/alignInCallExpression_after.py
@@ -0,0 +1,3 @@
+foo(1 +
+ x.
+ call())
\ No newline at end of file
diff --git a/python/testData/formatter/alignInNestedCallInWith.py b/python/testData/formatter/alignInNestedCallInWith.py
new file mode 100644
index 0000000..ccf3783
--- /dev/null
+++ b/python/testData/formatter/alignInNestedCallInWith.py
@@ -0,0 +1,10 @@
+import logging
+from nose.tools import assert_raises_regex
+
+
+def _assert_stuff(i):
+ with assert_raises_regex(
+ logging.INFO,
+ 'Did stuff to {} because of reasons that take up a whole line of text'.format(
+ i.relname)):
+ pass
\ No newline at end of file
diff --git a/python/testData/formatter/alignInNestedCallInWith_after.py b/python/testData/formatter/alignInNestedCallInWith_after.py
new file mode 100644
index 0000000..b64caa7
--- /dev/null
+++ b/python/testData/formatter/alignInNestedCallInWith_after.py
@@ -0,0 +1,10 @@
+import logging
+from nose.tools import assert_raises_regex
+
+
+def _assert_stuff(i):
+ with assert_raises_regex(
+ logging.INFO,
+ 'Did stuff to {} because of reasons that take up a whole line of text'.format(
+ i.relname)):
+ pass
\ No newline at end of file
diff --git a/python/testData/formatter/alignInParameterList.py b/python/testData/formatter/alignInParameterList.py
new file mode 100644
index 0000000..1a79766
--- /dev/null
+++ b/python/testData/formatter/alignInParameterList.py
@@ -0,0 +1,4 @@
+def foo(x=
+ y.
+ call()):
+ pass
\ No newline at end of file
diff --git a/python/testData/formatter/alignInParameterList_after.py b/python/testData/formatter/alignInParameterList_after.py
new file mode 100644
index 0000000..c3291b2
--- /dev/null
+++ b/python/testData/formatter/alignInParameterList_after.py
@@ -0,0 +1,4 @@
+def foo(x=
+ y.
+ call()):
+ pass
\ No newline at end of file
diff --git a/python/testData/formatter/alignInParenthesizedExpression.py b/python/testData/formatter/alignInParenthesizedExpression.py
new file mode 100644
index 0000000..ea97ade
--- /dev/null
+++ b/python/testData/formatter/alignInParenthesizedExpression.py
@@ -0,0 +1,8 @@
+print(1 + (1 + (1
+ +
+ x
+ .calc())
+ +
+ x.
+ calc()
+))
\ No newline at end of file
diff --git a/python/testData/formatter/alignInParenthesizedExpression_after.py b/python/testData/formatter/alignInParenthesizedExpression_after.py
new file mode 100644
index 0000000..868557c
--- /dev/null
+++ b/python/testData/formatter/alignInParenthesizedExpression_after.py
@@ -0,0 +1,8 @@
+print(1 + (1 + (1
+ +
+ x
+ .calc())
+ +
+ x.
+ calc()
+))
\ No newline at end of file
diff --git a/python/testData/formatter/commentInEmptyTuple.py b/python/testData/formatter/commentInEmptyTuple.py
new file mode 100644
index 0000000..fffda70
--- /dev/null
+++ b/python/testData/formatter/commentInEmptyTuple.py
@@ -0,0 +1,3 @@
+var_name = (
+# comment
+)
\ No newline at end of file
diff --git a/python/testData/formatter/commentInEmptyTuple_after.py b/python/testData/formatter/commentInEmptyTuple_after.py
new file mode 100644
index 0000000..a8572fd
--- /dev/null
+++ b/python/testData/formatter/commentInEmptyTuple_after.py
@@ -0,0 +1,3 @@
+var_name = (
+ # comment
+)
\ No newline at end of file
diff --git a/python/testData/formatter/continuationIndentInIndentingStatement.py b/python/testData/formatter/continuationIndentInIndentingStatement.py
index 5822bc4..38c7910 100644
--- a/python/testData/formatter/continuationIndentInIndentingStatement.py
+++ b/python/testData/formatter/continuationIndentInIndentingStatement.py
@@ -28,4 +28,12 @@
pass
except \
AttributeError:
+ pass
+
+while value \
+ in values: # <- missing continuation indent here
+ do_smth()
+
+if (1 + x.
+ value()):
pass
\ No newline at end of file
diff --git a/python/testData/formatter/continuationIndentInIndentingStatement2.py b/python/testData/formatter/continuationIndentInIndentingStatement2.py
new file mode 100644
index 0000000..63957fb
--- /dev/null
+++ b/python/testData/formatter/continuationIndentInIndentingStatement2.py
@@ -0,0 +1,4 @@
+def f(value, value1, value2):
+ if value in (
+ value1, value2) or value == 0: # <- missing continuation indent here
+ return False
\ No newline at end of file
diff --git a/python/testData/formatter/continuationIndentInIndentingStatement2_after.py b/python/testData/formatter/continuationIndentInIndentingStatement2_after.py
new file mode 100644
index 0000000..b76f2ac
--- /dev/null
+++ b/python/testData/formatter/continuationIndentInIndentingStatement2_after.py
@@ -0,0 +1,4 @@
+def f(value, value1, value2):
+ if value in (
+ value1, value2) or value == 0: # <- missing continuation indent here
+ return False
\ No newline at end of file
diff --git a/python/testData/formatter/continuationIndentInIndentingStatement_after.py b/python/testData/formatter/continuationIndentInIndentingStatement_after.py
index f38dd51..be17337 100644
--- a/python/testData/formatter/continuationIndentInIndentingStatement_after.py
+++ b/python/testData/formatter/continuationIndentInIndentingStatement_after.py
@@ -28,4 +28,12 @@
pass
except \
AttributeError:
+ pass
+
+while value \
+ in values: # <- missing continuation indent here
+ do_smth()
+
+if (1 + x.
+ value()):
pass
\ No newline at end of file
diff --git a/python/testData/formatter/wrapOnDot_after.py b/python/testData/formatter/wrapOnDot_after.py
index c4f7e7e..e42d177 100644
--- a/python/testData/formatter/wrapOnDot_after.py
+++ b/python/testData/formatter/wrapOnDot_after.py
@@ -1,2 +1,2 @@
sitesettings = call(settings_manager
- .get_whitelabel_settings_by_site_id(myuser.site_id))
\ No newline at end of file
+ .get_whitelabel_settings_by_site_id(myuser.site_id))
\ No newline at end of file
diff --git a/python/testData/highlighting/assignmentTargetWith.py b/python/testData/highlighting/assignmentTargetWith.py
index f516b41..f1e6493 100644
--- a/python/testData/highlighting/assignmentTargetWith.py
+++ b/python/testData/highlighting/assignmentTargetWith.py
@@ -1,2 +1,2 @@
-with open("") as <error descr="can't assign to operator">my_<<var</error>:
+with open("") as <error descr="Can't assign to operator">my_<<var</error>:
pass
\ No newline at end of file
diff --git a/python/testData/highlighting/assignmentTargets.py b/python/testData/highlighting/assignmentTargets.py
index 731541d..295cd8f 100644
--- a/python/testData/highlighting/assignmentTargets.py
+++ b/python/testData/highlighting/assignmentTargets.py
@@ -1,31 +1,31 @@
# fail
-<error descr="can't assign to function call">int(1)</error> = 1
+<error descr="Can't assign to function call">int(1)</error> = 1
-<error descr="can't assign to literal">12</error> = 1
+<error descr="Can't assign to literal">12</error> = 1
-<error descr="can't assign to operator">1 + 21</error> = 12
+<error descr="Can't assign to operator">1 + 21</error> = 12
-result = <error descr="can't assign to operator">a < c and c</error> = 4
+result = <error descr="Can't assign to operator">a < c and c</error> = 4
-<error descr="can't assign to ()">()</error> = 123
-<error descr="can't assign to []">[]</error> = 1
-[<error descr="can't assign to literal">1</error>] = 1
-<error descr="can't assign to literal">{}</error> = 1
-<error descr="can't assign to literal">{1, 2, 3}</error> = 1
+<error descr="Can't assign to ()">()</error> = 123
+<error descr="Can't assign to []">[]</error> = 1
+[<error descr="Can't assign to literal">1</error>] = 1
+<error descr="Can't assign to literal">{}</error> = 1
+<error descr="Can't assign to literal">{1, 2, 3}</error> = 1
-(<error descr="can't assign to literal">1</error>,(<error descr="can't assign to literal">2</error>, <error descr="can't assign to literal">3</error>)) = 3,(4,5)
-del <error descr="can't delete literal">1</error>
-del <error descr="can't delete function call">int()</error>
+(<error descr="Can't assign to literal">1</error>,(<error descr="Can't assign to literal">2</error>, <error descr="Can't assign to literal">3</error>)) = 3,(4,5)
+del <error descr="Can't delete literal">1</error>
+del <error descr="Can't delete function call">int()</error>
-for <error descr="can't assign to literal">1</error> in []:
+for <error descr="Can't assign to literal">1</error> in []:
pass
-for (<error descr="can't assign to literal">1</error>,(<error descr="can't assign to literal">2</error>,)) in [12]:
+for (<error descr="Can't assign to literal">1</error>,(<error descr="Can't assign to literal">2</error>,)) in [12]:
pass
-<error descr="augmented assign to dict comprehension not possible">{ x: y for y, x in ((1, 2), (3, 4)) }</error> += 5
-<error descr="can't assign to set comprehension">{ x for x in (1, 2) }</error> = 5
+<error descr="Augmented assign to dict comprehension not possible">{ x: y for y, x in ((1, 2), (3, 4)) }</error> += 5
+<error descr="Can't assign to set comprehension">{ x for x in (1, 2) }</error> = 5
# ok
diff --git a/python/testData/inspections/AddCallSuperAnnotations.py b/python/testData/inspections/AddCallSuperAnnotations.py
new file mode 100644
index 0000000..b50ae1b
--- /dev/null
+++ b/python/testData/inspections/AddCallSuperAnnotations.py
@@ -0,0 +1,8 @@
+class Example1:
+ def __init__(self, field1: str):
+ self.field1 = field1
+
+
+class Example2(Example1):
+ def <warning descr="Call to __init__ of super class is missed">__i<caret>nit__</warning>(self): ## Missed call to __init__ of super class
+ pass
\ No newline at end of file
diff --git a/python/testData/inspections/AddCallSuperAnnotations_after.py b/python/testData/inspections/AddCallSuperAnnotations_after.py
new file mode 100644
index 0000000..4bfd08c
--- /dev/null
+++ b/python/testData/inspections/AddCallSuperAnnotations_after.py
@@ -0,0 +1,8 @@
+class Example1:
+ def __init__(self, field1: str):
+ self.field1 = field1
+
+
+class Example2(Example1):
+ def __init__(self, field1):
+ super().__init__(field1)
\ No newline at end of file
diff --git a/python/testData/inspections/DictComprehensionToCall.py b/python/testData/inspections/DictComprehensionToCall.py
new file mode 100644
index 0000000..b360be79
--- /dev/null
+++ b/python/testData/inspections/DictComprehensionToCall.py
@@ -0,0 +1 @@
+var = <warning descr="Python version 2.4, 2.5, 2.6, 3.0 do not support dictionary comprehensions">{k: v for k, v in zip('abc', <caret>range(3)) if k % 2}</warning>
\ No newline at end of file
diff --git a/python/testData/inspections/DictComprehensionToCall_after.py b/python/testData/inspections/DictComprehensionToCall_after.py
new file mode 100644
index 0000000..a71f9ff
--- /dev/null
+++ b/python/testData/inspections/DictComprehensionToCall_after.py
@@ -0,0 +1 @@
+var = dict([(k, v) for k, v in zip('abc', range(3)) if k % 2])
\ No newline at end of file
diff --git a/python/testData/inspections/PyArgumentEqualDefaultInspection/test.py b/python/testData/inspections/PyArgumentEqualDefaultInspection/test.py
index bda25d32..b75341f 100644
--- a/python/testData/inspections/PyArgumentEqualDefaultInspection/test.py
+++ b/python/testData/inspections/PyArgumentEqualDefaultInspection/test.py
@@ -67,3 +67,9 @@
{1: 2}.get('foo', None) #pass
{1: 2}.pop('foo', None) #pass
+
+def a(foo=1*1024):
+ print foo
+
+a( 1024*1024)
+
diff --git a/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/bad.py b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/bad.py
new file mode 100644
index 0000000..c6492c1
--- /dev/null
+++ b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/bad.py
@@ -0,0 +1,62 @@
+i = []
+for i[0] in xrange(5):
+ for <weak_warning descr="Variable 'i[0]' already declared in 'for' loop or 'with' statement above">i[0]</weak_warning> in xrange(20, 25):
+ print("Inner", i)
+ for <weak_warning descr="Variable 'i' already declared in 'for' loop or 'with' statement above">i</weak_warning> in xrange(20, 25):
+ pass
+ print("Outer", i)
+
+for i in xrange(5):
+ for <weak_warning descr="Variable 'i' already declared in 'for' loop or 'with' statement above">i</weak_warning> in xrange(20, 25):
+ print("Inner", i)
+ print("Outer", i)
+
+for i in xrange(5):
+ i = []
+ for <weak_warning descr="Variable 'i[0]' already declared in 'for' loop or 'with' statement above">i[0]</weak_warning> in xrange(20, 25):
+ print("Inner", i)
+ print("Outer", i)
+
+i = [0]
+for i[0] in xrange(5):
+ for <weak_warning descr="Variable 'i[0]' already declared in 'for' loop or 'with' statement above">i[0]</weak_warning> in xrange(20, 25):
+ print("Inner", i)
+ print("Outer", i)
+
+i = [[]]
+for i[0] in xrange(5):
+ for <weak_warning descr="Variable 'i' already declared in 'for' loop or 'with' statement above">i</weak_warning> in xrange(20, 25):
+ print("Inner", i)
+ print("Outer", i)
+
+with open("a") as f:
+ spam(f)
+ f.eggs()
+ with open("b") as <weak_warning descr="Variable 'f' already declared in 'for' loop or 'with' statement above">f</weak_warning>: #
+ pass
+
+with open("a") as z, open("A") as f:
+ spam(f)
+ f.eggs()
+ for (a,b,c,d,(e,<weak_warning descr="Variable 'f' already declared in 'for' loop or 'with' statement above">f</weak_warning>)) in []:
+ pass
+
+
+with open("a") as f:
+ spam(f)
+ f.eggs()
+ for z in []:
+ with open("b") as q:
+ with open("a") as <weak_warning descr="Variable 'f' already declared in 'for' loop or 'with' statement above">f</weak_warning>: #
+ pass
+
+
+class Foo(object):
+ def __init__(self):
+ super(Foo, self).__init__()
+ self.data = "ddd"
+
+ def foo(self):
+ for self.data in [1,2,3]:
+ for <weak_warning descr="Variable 'self.data' already declared in 'for' loop or 'with' statement above">self.data</weak_warning> in [1,2,3]:
+ pass
\ No newline at end of file
diff --git a/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/good.py b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/good.py
new file mode 100644
index 0000000..f324656
--- /dev/null
+++ b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/good.py
@@ -0,0 +1,89 @@
+from spam import eggs
+
+for eggs in (1, 12):
+ eggs = 12
+
+for a in (1, 12):
+ for b in (2, 24):
+ for (c, d) in {"C": "D"}.items():
+ (e, f) = (a, d)
+
+i = 12
+print(i)
+(z, x) = (i, 12)
+print(z)
+
+for root in settings.STATICFILES_DIRS:
+ if isinstance(root, (list, tuple)):
+ prefix, root = root
+
+
+for field, model in self.model._meta.get_concrete_fields_with_model():
+ if model is None:
+ model = self.model
+
+with open('a', 'w') as a, open('b', 'w') as b:
+ do_something()
+
+
+for f in [1,2,3]:
+ f = f + 1
+
+for f in [1,2,3]:
+ f = spam(f)
+
+for f in [1,2,3]:
+ f = eggs(lambda x: x + f)
+
+q = []
+for q[0] in [1,2,3]:
+ q[0] = eggs(q)
+
+q = []
+for q[0] in [1,2,3]:
+ q[0] = eggs(q)
+
+for f in [1,2,3]:
+ f = eggs(lambda x: x, f)
+
+for a in [1,2]:
+ pass
+
+for a in [1,2]:
+ pass
+
+b = 12
+for b in [1,2]:
+ pass
+
+for item in range(5):
+ want_to_import = False
+ print want_to_import
+ want_to_import = 2 #No error should be here
+ if True:
+ pass
+
+for ((a, b), (c, d)) in {(1, 2): (3, 4)}.items():
+ print b
+
+x = [1]
+for x[0] in range(1,2):
+ print i
+
+for x[i] in range(1,2):
+ print i
+
+x = [[1]]
+for x[0][0] in range(1,2):
+ x[0][1] = 1
+
+class Foo(object):
+ def __init__(self):
+ super(Foo, self).__init__()
+ self.data = "ddd"
+
+ def foo(self):
+ data, self.data = self.data
+ for data in [1,2,3]:
+ for self.data in [1,2,3]:
+ pass
diff --git a/python/testData/inspections/PyPep8NamingInspection/globals.py b/python/testData/inspections/PyPep8NamingInspection/globals.py
new file mode 100644
index 0000000..c055acc
--- /dev/null
+++ b/python/testData/inspections/PyPep8NamingInspection/globals.py
@@ -0,0 +1,14 @@
+from contextlib import contextmanager
+
+MUST_REFRESH_CACHE = False
+
+
+@contextmanager
+def fresh_per_request_cache():
+ global MUST_REFRESH_CACHE
+ orig = MUST_REFRESH_CACHE
+ MUST_REFRESH_CACHE = True
+ try:
+ yield
+ finally:
+ MUST_REFRESH_CACHE = orig
\ No newline at end of file
diff --git a/python/testData/inspections/PyPep8NamingInspection/importCamelAsLower.py b/python/testData/inspections/PyPep8NamingInspection/importCamelAsLower.py
index 94a1139..77c27c7 100644
--- a/python/testData/inspections/PyPep8NamingInspection/importCamelAsLower.py
+++ b/python/testData/inspections/PyPep8NamingInspection/importCamelAsLower.py
@@ -1 +1,2 @@
from x import TestX as <weak_warning descr="CamelCase variable imported as lowercase">test</weak_warning>
+import Exceptions.tt as user_defined_properties
diff --git a/python/testData/inspections/PyPropertyAccessInspection/test.py b/python/testData/inspections/PyPropertyAccessInspection/test.py
index a42b78f..c140b8a 100644
--- a/python/testData/inspections/PyPropertyAccessInspection/test.py
+++ b/python/testData/inspections/PyPropertyAccessInspection/test.py
@@ -22,7 +22,7 @@
<warning descr="Property 'readonly' cannot be set">a.readonly</warning> += 1
del <warning descr="Property 'readonly' cannot be deleted">a.readonly</warning>
-del <error descr="can't delete function call">a.readonly()</error> # Error, delete the result of function
+del <error descr="Can't delete function call">a.readonly()</error> # Error, delete the result of function
a.writeonly = 1
<warning descr="Property 'writeonly' cannot be read">a.writeonly</warning> += 1
diff --git a/python/testData/inspections/PyTypeCheckerInspection/MetaClassIteration.py b/python/testData/inspections/PyTypeCheckerInspection/MetaClassIteration.py
new file mode 100644
index 0000000..0ec6926
--- /dev/null
+++ b/python/testData/inspections/PyTypeCheckerInspection/MetaClassIteration.py
@@ -0,0 +1,31 @@
+class M1(type):
+ def __iter__(self):
+ pass
+
+
+class M2(type):
+ pass
+
+
+class C1(object):
+ __metaclass__ = M1
+
+
+class C2(object):
+ __metaclass__ = M2
+
+
+class B1(C1):
+ pass
+
+
+for x in C1:
+ pass
+
+
+for y in <warning descr="Expected 'collections.Iterable', got 'C2' instead">C2</warning>:
+ pass
+
+
+for z in B1:
+ pass
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/FromPackageImportBuiltin/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection/FromPackageImportBuiltin/a.py
index a66445c..8880a48 100644
--- a/python/testData/inspections/PyUnresolvedReferencesInspection/FromPackageImportBuiltin/a.py
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/FromPackageImportBuiltin/a.py
@@ -1 +1,3 @@
from importSource import <error descr="Unresolved reference 'len'">len</error>
+
+len()
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImported/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImported/a.py
new file mode 100644
index 0000000..b0ad821
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImported/a.py
@@ -0,0 +1 @@
+<warning descr="Unused import statement">from my_module import <error descr="Unresolved reference 'eggs'">eggs</error></warning>
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImported/my_module.py b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImported/my_module.py
new file mode 100644
index 0000000..51d8ead
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImported/my_module.py
@@ -0,0 +1,2 @@
+def my_func():
+ pass
\ No newline at end of file
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImportedSeveralTimes/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImportedSeveralTimes/a.py
new file mode 100644
index 0000000..5e1c928
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImportedSeveralTimes/a.py
@@ -0,0 +1,2 @@
+<warning descr="Unused import statement">from my_module import <error descr="Unresolved reference 'eggs'">eggs</error></warning>
+<warning descr="Unused import statement">from my_module import <error descr="Unresolved reference 'eggs'">eggs</error></warning>
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImportedSeveralTimes/my_module.py b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImportedSeveralTimes/my_module.py
new file mode 100644
index 0000000..51d8ead
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedUnresolvedNameImportedSeveralTimes/my_module.py
@@ -0,0 +1,2 @@
+def my_func():
+ pass
\ No newline at end of file
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/UsedUnresolvedNameImportedSeveralTimes/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection/UsedUnresolvedNameImportedSeveralTimes/a.py
new file mode 100644
index 0000000..767f9bf
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/UsedUnresolvedNameImportedSeveralTimes/a.py
@@ -0,0 +1,4 @@
+from my_package.my_module import <error descr="Unresolved reference 'eggs'">eggs</error>
+from my_package.my_module import <error descr="Unresolved reference 'eggs'">eggs</error>
+
+eggs()
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/UsedUnresolvedNameImportedSeveralTimes/my_package/__init__.py b/python/testData/inspections/PyUnresolvedReferencesInspection/UsedUnresolvedNameImportedSeveralTimes/my_package/__init__.py
new file mode 100644
index 0000000..a5f9f02
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/UsedUnresolvedNameImportedSeveralTimes/my_package/__init__.py
@@ -0,0 +1 @@
+__author__ = 'Ilya.Kazakevich'
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/UsedUnresolvedNameImportedSeveralTimes/my_package/my_module.py b/python/testData/inspections/PyUnresolvedReferencesInspection/UsedUnresolvedNameImportedSeveralTimes/my_package/my_module.py
new file mode 100644
index 0000000..51d8ead
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/UsedUnresolvedNameImportedSeveralTimes/my_package/my_module.py
@@ -0,0 +1,2 @@
+def my_func():
+ pass
\ No newline at end of file
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/importFunction.py b/python/testData/inspections/PyUnresolvedReferencesInspection/importFunction.py
index 2bfbaa3..75ddd5c 100644
--- a/python/testData/inspections/PyUnresolvedReferencesInspection/importFunction.py
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/importFunction.py
@@ -1 +1,3 @@
import collections.<warning descr="No module named OrderedDict">OrderedDict</warning>
+
+collections.OrderedDict()
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImport.py b/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImport.py
index e96da63..91aae42 100644
--- a/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImport.py
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/unresolvedImport.py
@@ -1 +1,3 @@
import <error descr="No module named wurm">wurm</error>
+
+wurm()
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/unusedUnresolvedModuleImported.py b/python/testData/inspections/PyUnresolvedReferencesInspection/unusedUnresolvedModuleImported.py
new file mode 100644
index 0000000..3351b1d
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/unusedUnresolvedModuleImported.py
@@ -0,0 +1 @@
+<warning descr="Unused import statement">import <error descr="No module named spam">spam</error></warning>
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/unusedUnresolvedPackageImported.py b/python/testData/inspections/PyUnresolvedReferencesInspection/unusedUnresolvedPackageImported.py
new file mode 100644
index 0000000..ba929a6
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection/unusedUnresolvedPackageImported.py
@@ -0,0 +1 @@
+<warning descr="Unused import statement">import <error descr="No module named spam">spam</error>.eggs</warning>
\ No newline at end of file
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/EnumMemberAttributes/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/EnumMemberAttributes/a.py
new file mode 100644
index 0000000..9d4ffeb
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection3K/EnumMemberAttributes/a.py
@@ -0,0 +1,18 @@
+from enum import Enum
+
+
+class Color(Enum):
+ red = 1
+ green = 2
+ blue = 3
+
+
+print(Color.red.name, Color.red.name.upper())
+print(Color.red.name.<warning descr="Unresolved attribute reference 'foo' for class 'str'">foo</warning>)
+print(Color.red.value, Color.red.value.real)
+print(Color.red.value.<warning descr="Unresolved attribute reference 'foo' for class 'int'">foo</warning>)
+print(Color.red.<warning descr="Unresolved attribute reference 'foo' for class 'Color'">foo</warning>)
+
+
+print(Color.__members__.items())
+print(Color.__members__.<warning descr="Unresolved attribute reference 'foo' for class 'dict'">foo</warning>)
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/EnumMemberAttributes/enum.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/EnumMemberAttributes/enum.py
new file mode 100644
index 0000000..368f85a
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection3K/EnumMemberAttributes/enum.py
@@ -0,0 +1,17 @@
+class EnumMeta(type):
+ """Fake Enum metaclass."""
+ @property
+ def __members__(cls):
+ return {}
+
+
+class Enum(object, metaclass=EnumMeta):
+ """Fake Enum class."""
+
+ @DynamicClassAttribute
+ def name(self):
+ return self._name_
+
+ @DynamicClassAttribute
+ def value(self):
+ return self._value_
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/a.py
new file mode 100644
index 0000000..bf0ee44
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/a.py
@@ -0,0 +1,5 @@
+from m1 import C
+
+c = C()
+print(C.foo(), C.<warning descr="Unresolved attribute reference 'bar' for class 'C'">bar</warning>())
+print(c.<warning descr="Unresolved attribute reference 'foo' for class 'C'">foo</warning>())
\ No newline at end of file
diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/m1.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/m1.py
new file mode 100644
index 0000000..bd6222a
--- /dev/null
+++ b/python/testData/inspections/PyUnresolvedReferencesInspection3K/MetaclassStub/m1.py
@@ -0,0 +1,7 @@
+class M(type):
+ def foo(cls):
+ pass
+
+
+class C(metaclass=M):
+ pass
diff --git a/python/testData/inspections/QualifyByImport_after.py b/python/testData/inspections/QualifyByImport_after.py
index 7718df7..aa433ef 100644
--- a/python/testData/inspections/QualifyByImport_after.py
+++ b/python/testData/inspections/QualifyByImport_after.py
@@ -1,3 +1,3 @@
import QualifyByImportFoo
-QualifyByImportFoo.foo # must be qualified
+QualifyByImportFoo.foo # must be qualified
diff --git a/python/testData/inspections/UnresolvedRefNoCreateFunction.py b/python/testData/inspections/UnresolvedRefNoCreateFunction.py
new file mode 100644
index 0000000..ae313c0
--- /dev/null
+++ b/python/testData/inspections/UnresolvedRefNoCreateFunction.py
@@ -0,0 +1 @@
+<error descr="Unresolved reference 'my_ref'">my_<caret>ref</error>.do_smth(1, 2)
\ No newline at end of file
diff --git a/python/testData/keywordCompletion/finallyInElse.after.py b/python/testData/keywordCompletion/finallyInElse.after.py
new file mode 100644
index 0000000..be2ee7a
--- /dev/null
+++ b/python/testData/keywordCompletion/finallyInElse.after.py
@@ -0,0 +1,8 @@
+def f():
+ try:
+ a = 1
+ except:
+ b = 1
+ else:
+ c = 1
+ finally:
\ No newline at end of file
diff --git a/python/testData/keywordCompletion/finallyInElse.py b/python/testData/keywordCompletion/finallyInElse.py
new file mode 100644
index 0000000..5f170c7
--- /dev/null
+++ b/python/testData/keywordCompletion/finallyInElse.py
@@ -0,0 +1,8 @@
+def f():
+ try:
+ a = 1
+ except:
+ b = 1
+ else:
+ c = 1
+ fin<caret>
\ No newline at end of file
diff --git a/python/testData/optimizeImports/insertBlankLines.after.py b/python/testData/optimizeImports/insertBlankLines.after.py
index e3719e0..62bebf5 100644
--- a/python/testData/optimizeImports/insertBlankLines.after.py
+++ b/python/testData/optimizeImports/insertBlankLines.after.py
@@ -8,3 +8,4 @@
sys.path
datetime.datetime
+foo.bar()
\ No newline at end of file
diff --git a/python/testData/optimizeImports/insertBlankLines.py b/python/testData/optimizeImports/insertBlankLines.py
index 9e77f44..fcf075f 100644
--- a/python/testData/optimizeImports/insertBlankLines.py
+++ b/python/testData/optimizeImports/insertBlankLines.py
@@ -7,3 +7,4 @@
sys.path
datetime.datetime
+foo.bar()
\ No newline at end of file
diff --git a/python/testData/optimizeImports/order.after.py b/python/testData/optimizeImports/order.after.py
index e3719e0..62bebf5 100644
--- a/python/testData/optimizeImports/order.after.py
+++ b/python/testData/optimizeImports/order.after.py
@@ -8,3 +8,4 @@
sys.path
datetime.datetime
+foo.bar()
\ No newline at end of file
diff --git a/python/testData/optimizeImports/order.py b/python/testData/optimizeImports/order.py
index ad3147a..eaa3e27 100644
--- a/python/testData/optimizeImports/order.py
+++ b/python/testData/optimizeImports/order.py
@@ -6,3 +6,4 @@
sys.path
datetime.datetime
+foo.bar()
\ No newline at end of file
diff --git a/python/testData/optimizeImports/unresolved.after.py b/python/testData/optimizeImports/unresolved.after.py
index b014e1f..8b13789 100644
--- a/python/testData/optimizeImports/unresolved.after.py
+++ b/python/testData/optimizeImports/unresolved.after.py
@@ -1 +1 @@
-import xyzzy_shazam
+
diff --git a/python/testData/override/docstring.py b/python/testData/override/docstring.py
new file mode 100644
index 0000000..3670ee1
--- /dev/null
+++ b/python/testData/override/docstring.py
@@ -0,0 +1,9 @@
+class Abstract(object):
+
+ @abstractmethod
+ def foo(self, bar):
+ pass
+
+
+class Concrete(Abstract):
+ """The docstring."""
\ No newline at end of file
diff --git a/python/testData/override/docstring_after.py b/python/testData/override/docstring_after.py
new file mode 100644
index 0000000..a8b3696
--- /dev/null
+++ b/python/testData/override/docstring_after.py
@@ -0,0 +1,12 @@
+class Abstract(object):
+
+ @abstractmethod
+ def foo(self, bar):
+ pass
+
+
+class Concrete(Abstract):
+ """The docstring."""
+
+ def foo(self, bar):
+ <selection>super(Concrete, self).foo(bar)</selection>
\ No newline at end of file
diff --git a/python/testData/psi/WithMissingID.txt b/python/testData/psi/WithMissingID.txt
index fa8caab..afd37e7 100644
--- a/python/testData/psi/WithMissingID.txt
+++ b/python/testData/psi/WithMissingID.txt
@@ -13,7 +13,7 @@
PsiElement(Py:RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(Py:AS_KEYWORD)('as')
- PsiErrorElement:identifier expected
+ PsiErrorElement:Identifier expected
<empty list>
PsiWhiteSpace(' ')
PsiElement(Py:COLON)(':')
diff --git a/python/testData/refactoring/extractmethod/Comment2.after.py b/python/testData/refactoring/extractmethod/Comment2.after.py
index 1260973..5e5fdc3 100644
--- a/python/testData/refactoring/extractmethod/Comment2.after.py
+++ b/python/testData/refactoring/extractmethod/Comment2.after.py
@@ -1,6 +1,6 @@
class Foo():
def baz():
- tmp = "!" #try to extract this assignmet, either with or without this comment
+ tmp = "!" #try to extract this assignmet, either with or without this comment
baz()
diff --git a/python/testData/refactoring/extractmethod/ElseBody.after.py b/python/testData/refactoring/extractmethod/ElseBody.after.py
index 684a444..57b5fa01 100644
--- a/python/testData/refactoring/extractmethod/ElseBody.after.py
+++ b/python/testData/refactoring/extractmethod/ElseBody.after.py
@@ -1,5 +1,5 @@
def baz(f_new):
- length = len(f_new.readlines()) #<---extract something from here
+ length = len(f_new.readlines()) #<---extract something from here
print("hi from else")
diff --git a/python/testData/refactoring/rename/docstringParams.py b/python/testData/refactoring/rename/docstringParams.py
new file mode 100644
index 0000000..4a79b84
--- /dev/null
+++ b/python/testData/refactoring/rename/docstringParams.py
@@ -0,0 +1,9 @@
+class SomeClass(object):
+ """ Awesome class
+
+ @ivar someVar: great stuff
+ @type someVar: string
+ """
+
+ def __init__(self):
+ self.some<caret>Var = None
\ No newline at end of file
diff --git a/python/testData/refactoring/rename/docstringParams_after.py b/python/testData/refactoring/rename/docstringParams_after.py
new file mode 100644
index 0000000..ae4d5e5
--- /dev/null
+++ b/python/testData/refactoring/rename/docstringParams_after.py
@@ -0,0 +1,9 @@
+class SomeClass(object):
+ """ Awesome class
+
+ @ivar bar: great stuff
+ @type bar: string
+ """
+
+ def __init__(self):
+ self.bar = None
\ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/python/PyFormatterTest.java b/python/testSrc/com/jetbrains/python/PyFormatterTest.java
index 3ca878b..2fdd39c 100644
--- a/python/testSrc/com/jetbrains/python/PyFormatterTest.java
+++ b/python/testSrc/com/jetbrains/python/PyFormatterTest.java
@@ -118,6 +118,10 @@
doTest();
}
+ public void testCommentInEmptyTuple() { //PY-11904
+ doTest();
+ }
+
public void testTwoLinesBetweenTopLevelClasses() { // PY-2765
doTest();
}
@@ -207,6 +211,10 @@
doTest();
}
+ public void testContinuationIndentInIndentingStatement2() { // PY-11868
+ doTest();
+ }
+
public void testBlankLineAfterDecorator() {
doTest();
}
@@ -291,6 +299,14 @@
doTest();
}
+ public void testAlignInCallExpression() {
+ doTest();
+ }
+
+ public void _testAlignInNestedCallInWith() { //PY-11337 TODO:
+ doTest();
+ }
+
public void testContinuationIndentForCallInStatementPart() { // PY-8577
doTest();
}
@@ -298,8 +314,8 @@
public void testIfConditionContinuation() { // PY-8195
doTest();
}
-
- public void _testIndentInNestedCall() { // PY-8195
+
+ public void _testIndentInNestedCall() { // PY-11919 TODO: required changes in formatter to be able to make indent relative to block or alignment
doTest();
}
@@ -370,6 +386,14 @@
doTest();
}
+ public void testAlignInParenthesizedExpression() {
+ doTest();
+ }
+
+ public void testAlignInParameterList() {
+ doTest();
+ }
+
private void doTest() {
doTest(false);
}
diff --git a/python/testSrc/com/jetbrains/python/PyOverrideTest.java b/python/testSrc/com/jetbrains/python/PyOverrideTest.java
index ed7fc43..d86f25d 100644
--- a/python/testSrc/com/jetbrains/python/PyOverrideTest.java
+++ b/python/testSrc/com/jetbrains/python/PyOverrideTest.java
@@ -130,6 +130,10 @@
doTest3k();
}
+ public void testDocstring() {
+ doTest();
+ }
+
// PY-10229
public void testInstanceCheck() {
myFixture.configureByFile("override/" + getTestName(true) + ".py");
diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
index 4083775..2d97250 100644
--- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
+++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java
@@ -266,6 +266,15 @@
PyBundle.message("QFIX.unresolved.reference.create.function.$0", "ref"), true, true);
}
+ public void testUnresolvedRefNoCreateFunction() {
+ myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
+ myFixture.configureByFile("UnresolvedRefNoCreateFunction.py");
+ myFixture.checkHighlighting(true, false, false);
+ final IntentionAction intentionAction = myFixture.getAvailableIntention(
+ PyBundle.message("QFIX.unresolved.reference.create.function.$0", "ref"));
+ assertNull(intentionAction);
+ }
+
public void testReplaceNotEqOperator() {
doInspectionTest("ReplaceNotEqOperator.py", PyCompatibilityInspection.class,
PyBundle.message("INTN.replace.noteq.operator"), true, true);
@@ -306,6 +315,17 @@
PyBundle.message("QFIX.add.super"), true, true);
}
+ public void testAddCallSuperAnnotations() {
+ runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() {
+ @Override
+ public void run() {
+ doInspectionTest("AddCallSuperAnnotations.py",
+ PyMissingConstructorInspection.class,
+ PyBundle.message("QFIX.add.super"), true, true);
+ }
+ });
+ }
+
public void testAddCallSuperPass() { //PY-8654
doInspectionTest("AddCallSuperPass.py", PyMissingConstructorInspection.class,
PyBundle.message("QFIX.add.super"), true, true);
@@ -342,6 +362,11 @@
PyBundle.message("QFIX.replace.function.set.with.literal"), true, true);
}
+ public void testDictComprehensionToCall() {
+ doInspectionTest("DictComprehensionToCall.py", PyCompatibilityInspection.class,
+ PyBundle.message("INTN.convert.dict.comp.to"), true, true);
+ }
+
public void testDocstringParams() { //PY-3394
PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(myFixture.getModule());
documentationSettings.setFormat(DocStringFormat.EPYTEXT);
diff --git a/python/testSrc/com/jetbrains/python/PyRegexpTest.java b/python/testSrc/com/jetbrains/python/PyRegexpTest.java
index 3befb2c..cce3941 100644
--- a/python/testSrc/com/jetbrains/python/PyRegexpTest.java
+++ b/python/testSrc/com/jetbrains/python/PyRegexpTest.java
@@ -127,7 +127,7 @@
"\n" +
"def f(x, y):\n" +
" re.search('<caret>.*(' + x + ')' + y, 'foo')\n",
- ".*(missing)missing");
+ ".*(missing_value)missing_value");
}
public void testPercentFormattingRegexpAutoInjection() {
@@ -135,7 +135,7 @@
"\n" +
"def f(x, y):\n" +
" re.search('<caret>.*%s-%d' % (x, y), 'foo')\n",
- ".*missing-missing");
+ ".*missing_value-missing_value");
}
public void testNewStyleFormattingRegexpAutoInjection() {
@@ -143,7 +143,7 @@
"\n" +
"def f(x, y):\n" +
" re.search('<caret>.*{foo}-{}'.format(x, foo=y), 'foo')\n",
- ".*missing-missing");
+ ".*missing_value-missing_value");
}
public void testNewStyleFormattingEndsWithConstant() {
@@ -151,7 +151,7 @@
"\n" +
"def f(**kwargs):" +
" re.search('<caret>(foo{bar}baz$)'.format(**kwargs), 'foo')\n",
- "(foomissingbaz$)");
+ "(foomissing_valuebaz$)");
}
private void doTestInjectedText(@NotNull String text, @NotNull String expected) {
diff --git a/python/testSrc/com/jetbrains/python/PyStringFormatParserTest.java b/python/testSrc/com/jetbrains/python/PyStringFormatParserTest.java
index 16fefc3..b6aa969 100644
--- a/python/testSrc/com/jetbrains/python/PyStringFormatParserTest.java
+++ b/python/testSrc/com/jetbrains/python/PyStringFormatParserTest.java
@@ -146,4 +146,17 @@
assertEquals(1, chunks.size());
assertConstant(chunks.get(0), 0, 1);
}
+
+ public void testNewStyleUnbalanced() {
+ final List<FormatStringChunk> chunks = parseNewStyleFormat("{{{foo}}");
+ assertEquals(2, chunks.size());
+ }
+
+ public void testNewStyleEscapingAndValue() {
+ final List<FormatStringChunk> chunks = parseNewStyleFormat("{{{foo}}}");
+ assertEquals(3, chunks.size());
+ assertEquals(TextRange.create(0, 2), chunks.get(0).getTextRange());
+ assertEquals(TextRange.create(2, 7), chunks.get(1).getTextRange());
+ assertEquals(TextRange.create(7, 9), chunks.get(2).getTextRange());
+ }
}
diff --git a/python/testSrc/com/jetbrains/python/PyStringLiteralTest.java b/python/testSrc/com/jetbrains/python/PyStringLiteralTest.java
index 3933584..2be57da 100644
--- a/python/testSrc/com/jetbrains/python/PyStringLiteralTest.java
+++ b/python/testSrc/com/jetbrains/python/PyStringLiteralTest.java
@@ -115,6 +115,21 @@
assertEquals(-1, escaper.getOffsetInHost(9, range));
}
+ public void testStringValue() {
+ assertEquals("foo", createLiteralFromText("\"\"\"foo\"\"\"").getStringValue());
+ assertEquals("foo", createLiteralFromText("u\"foo\"").getStringValue());
+ assertEquals("foo", createLiteralFromText("b\"foo\"").getStringValue());
+ assertEquals("\\b", createLiteralFromText("r'\\b'").getStringValue());
+ assertEquals("b\\n", createLiteralFromText("ur'\\u0062\\n'").getStringValue());
+ assertEquals("\\8", createLiteralFromText("'\\8'").getStringValue());
+ }
+
+ public void testEscapedUnicodeInLiterals() {
+ assertEquals("\\u0041", createLiteralFromText("'\\u0041'").getStringValue());
+ assertEquals("A", createLiteralFromText("u'\\u0041'").getStringValue());
+ assertEquals("\\u0041", createLiteralFromText("b'\\u0041'").getStringValue());
+ }
+
private static String decodeRange(PyStringLiteralExpression expr, TextRange range) {
final StringBuilder builder = new StringBuilder();
expr.createLiteralTextEscaper().decode(range, builder);
@@ -128,15 +143,6 @@
return expr;
}
- public void testStringValue() {
- assertEquals("foo", createLiteralFromText("\"\"\"foo\"\"\"").getStringValue());
- assertEquals("foo", createLiteralFromText("u\"foo\"").getStringValue());
- assertEquals("foo", createLiteralFromText("b\"foo\"").getStringValue());
- assertEquals("\\b", createLiteralFromText("r'\\b'").getStringValue());
- assertEquals("b\\n", createLiteralFromText("ur'\\u0062\\n'").getStringValue());
- assertEquals("\\8", createLiteralFromText("'\\8'").getStringValue());
- }
-
private List<String> getCharacterRanges(String text) {
final PyStringLiteralExpression expr = createLiteralFromText(text);
assertNotNull(expr);
diff --git a/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java
index a439727..acf6cc7 100644
--- a/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java
@@ -124,8 +124,8 @@
public void testNoElseBeforeExcept() {
final List<String> lookupElementStrings = doTestByText("try:\n" +
- " a = 1\n" +
- "<caret>");
+ " a = 1\n" +
+ "<caret>");
assertNotNull(lookupElementStrings);
assertDoesntContain(lookupElementStrings, "else");
}
@@ -169,6 +169,10 @@
"el<caret>").contains("else"));
}
+ public void testFinallyInElse() { // PY-6755
+ doTest();
+ }
+
public void testForInComprehension() { // PY-3687
assertContainsElements(doTestByText("L = [x fo<caret>]"), "for");
assertContainsElements(doTestByText("L = [x <caret>]"), "for");
diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyInspectionTestCase.java b/python/testSrc/com/jetbrains/python/fixtures/PyInspectionTestCase.java
new file mode 100644
index 0000000..717a579
--- /dev/null
+++ b/python/testSrc/com/jetbrains/python/fixtures/PyInspectionTestCase.java
@@ -0,0 +1,61 @@
+package com.jetbrains.python.fixtures;
+
+import com.jetbrains.python.inspections.PyInspection;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Helps you to create inspection tests.
+ * <br/>
+ * For each case
+ * <ol>
+ * <li>Create file <code>testData/inspections/_YOUR_INSPECTION_CLASS_SIMPLE_NAME_/CASE_NAME_CAMEL_CASE.py</code></li>
+ * <li>Create method <code>test_YOUR_CASE_NAME_PASCAL_CASE</code> that runs {@link #doTest()}</li>
+ * <li>Overwrite {@link #isInfo()}, {@link #isWarning()} or {@link #isWeakWarning()} to configure what to check</li>
+ * </ol>
+ *
+ * @author link
+ */
+public abstract class PyInspectionTestCase extends PyTestCase {
+
+ @NotNull
+ protected abstract Class<? extends PyInspection> getInspectionClass();
+
+ /**
+ * Launches test. To be called by test author
+ */
+ protected void doTest() {
+ myFixture.configureByFile(getTestDirectory(true) + ".py");
+ configureInspection();
+ }
+
+ protected void doMultiFileTest() {
+ doMultiFileTest("a.py");
+ }
+ protected void doMultiFileTest(@NotNull String filename) {
+ myFixture.copyDirectoryToProject(getTestDirectory(false), "");
+ myFixture.configureFromTempProjectFile(filename);
+ configureInspection();
+ }
+
+ private void configureInspection() {
+ myFixture.enableInspections(getInspectionClass());
+ myFixture.checkHighlighting(isWarning(), isInfo(), isWeakWarning());
+ }
+
+ private String getTestDirectory(boolean lowercaseFirstLetter) {
+ return "inspections/" + getInspectionClass().getSimpleName() + "/" + getTestName(lowercaseFirstLetter);
+ }
+
+
+ protected boolean isWeakWarning() {
+ return true;
+ }
+
+ protected boolean isInfo() {
+ return false;
+ }
+
+ protected boolean isWarning() {
+ return true;
+ }
+}
diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java
index 65cb17d..ee37eab 100644
--- a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java
@@ -15,11 +15,19 @@
*/
package com.jetbrains.python.inspections;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.testFramework.LightProjectDescriptor;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.LanguageLevel;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.stubs.PyClassNameIndex;
import org.jetbrains.annotations.NotNull;
+import java.util.Collection;
+
/**
* @author vlan
*/
@@ -73,6 +81,18 @@
doTest();
}
+ public void testMetaclassStub() {
+ doMultiFileTest("a.py");
+ final Project project = myFixture.getProject();
+ Collection<PyClass> classes = PyClassNameIndex.find("M", project, GlobalSearchScope.allScope(project));
+ for (PyClass cls : classes) {
+ final PsiFile file = cls.getContainingFile();
+ if (file instanceof PyFile) {
+ assertNotParsed((PyFile)file);
+ }
+ }
+ }
+
// PY-9011
public void testDatetimeDateAttributesOutsideClass() {
doMultiFileTest("a.py");
@@ -81,4 +101,8 @@
public void testObjectNewAttributes() {
doTest();
}
+
+ public void testEnumMemberAttributes() {
+ doMultiFileTest("a.py");
+ }
}
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspectionTest.java
new file mode 100644
index 0000000..2870935
--- /dev/null
+++ b/python/testSrc/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspectionTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.inspections;
+
+import com.jetbrains.python.fixtures.PyInspectionTestCase;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author link
+ */
+public class PyAssignmentToLoopOrWithParameterInspectionTest extends PyInspectionTestCase {
+
+ public void testGood() {
+ doTest();
+ }
+
+ public void testBad() {
+ doTest();
+ }
+
+ @NotNull
+ @Override
+ protected Class<? extends PyInspection> getInspectionClass() {
+ return PyAssignmentToLoopOrWithParameterInspection.class;
+ }
+
+ @Override
+ protected boolean isWeakWarning() {
+ return true;
+ }
+}
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyPep8NamingInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyPep8NamingInspectionTest.java
index d048af2..0a32aa4 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyPep8NamingInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyPep8NamingInspectionTest.java
@@ -54,6 +54,10 @@
doTest();
}
+ public void testGlobals() {
+ doTest();
+ }
+
public void testTest() {
doTest();
}
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java
index 2615cc1..0e09054 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java
@@ -228,4 +228,8 @@
public void testSecondFormIter() {
doTest();
}
+
+ public void testMetaClassIteration() {
+ doTest();
+ }
}
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
index 53bcbc3..546795e 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java
@@ -15,15 +15,14 @@
*/
package com.jetbrains.python.inspections;
-import com.jetbrains.python.fixtures.PyTestCase;
+import com.jetbrains.python.fixtures.PyInspectionTestCase;
import com.jetbrains.python.psi.LanguageLevel;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
-public class PyUnresolvedReferencesInspectionTest extends PyTestCase {
- private static final String TEST_DIRECTORY = "inspections/PyUnresolvedReferencesInspection/";
+public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase {
public void testSelfReference() {
doTest();
@@ -77,11 +76,11 @@
public void testTypeAssertions() {
doTest();
}
-
+
public void testUnresolvedImportedModule() { // PY-2075
doTest();
}
-
+
public void testSuperType() { // PY-2320
doTest();
}
@@ -89,7 +88,7 @@
public void testImportFunction() { // PY-1896
doTest();
}
-
+
public void testSuperclassAsLocal() { // PY-5427
doTest();
}
@@ -336,17 +335,34 @@
doTest();
}
- private void doTest() {
- myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py");
- myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
- myFixture.checkHighlighting(true, false, false);
+ // PY-6955
+ public void testUnusedUnresolvedModuleImported() {
+ doTest();
}
- private void doMultiFileTest(@NotNull String filename) {
- final String testName = getTestName(false);
- myFixture.copyDirectoryToProject(TEST_DIRECTORY + testName, "");
- myFixture.configureFromTempProjectFile(filename);
- myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
- myFixture.checkHighlighting(true, false, false);
+ // PY-6955
+ public void testUnusedUnresolvedNameImported() {
+ doMultiFileTest();
+ }
+
+ // PY-6955
+ public void testUnusedUnresolvedNameImportedSeveralTimes() {
+ doMultiFileTest();
+ }
+
+ // PY-6955
+ public void testUsedUnresolvedNameImportedSeveralTimes() {
+ doMultiFileTest();
+ }
+
+ // PY-6955
+ public void testUnusedUnresolvedPackageImported() {
+ doTest();
+ }
+
+ @NotNull
+ @Override
+ protected Class<? extends PyInspection> getInspectionClass() {
+ return PyUnresolvedReferencesInspection.class;
}
}
diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java
index f6ff0ee..948f159 100644
--- a/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java
+++ b/python/testSrc/com/jetbrains/python/refactoring/PyRenameTest.java
@@ -195,6 +195,11 @@
doMultiFileTest("bar");
}
+ // PY-11879
+ public void testDocstringParams() {
+ doTest("bar");
+ }
+
private void doRenameConflictTest(String newName, String expectedConflict) {
myFixture.configureByFile(RENAME_DATA_PATH + getTestName(true) + ".py");
try {