diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index 411cc3d5720a..f53181ad8e54 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -387,9 +387,10 @@ public class BuildManager implements ApplicationComponent{ } public void clearState(Project project) { - cancelPreloadedBuilds(project); - final String projectPath = getProjectPath(project); + + cancelPreloadedBuilds(projectPath); + synchronized (myProjectDataMap) { final ProjectData data = myProjectDataMap.get(projectPath); if (data != null) { @@ -544,8 +545,7 @@ public class BuildManager implements ApplicationComponent{ return futures; } - private void cancelPreloadedBuilds(Project project) { - final String projectPath = getProjectPath(project); + private void cancelPreloadedBuilds(final String projectPath) { runCommand(new Runnable() { @Override public void run() { @@ -632,12 +632,7 @@ public class BuildManager implements ApplicationComponent{ sessionId = UUID.randomUUID(); } - final RequestFuture future = usingPreloadedProcess? preloadedFuture : new RequestFuture(handler, sessionId, new RequestFuture.CancelAction() { - @Override - public void cancel(RequestFuture future) throws Exception { - myMessageDispatcher.cancelSession(future.getRequestID()); - } - }); + final RequestFuture future = usingPreloadedProcess? preloadedFuture : new RequestFuture(handler, sessionId, new CancelBuildSessionAction()); _future.setDelegate(future); if (!usingPreloadedProcess && (future.isCancelled() || project.isDisposed())) { @@ -833,12 +828,7 @@ public class BuildManager implements ApplicationComponent{ // launching build process from projectTaskQueue ensures that no other build process for this project is currently running return projectTaskQueue.submit(new Callable, OSProcessHandler>>() { public Pair, OSProcessHandler> call() throws Exception { - final RequestFuture future = new RequestFuture(new PreloadedProcessMessageHandler(project), UUID.randomUUID(), new RequestFuture.CancelAction() { - @Override - public void cancel(RequestFuture future) throws Exception { - myMessageDispatcher.cancelSession(future.getRequestID()); - } - }); + final RequestFuture future = new RequestFuture(new PreloadedProcessMessageHandler(), UUID.randomUUID(), new CancelBuildSessionAction()); try { myMessageDispatcher.registerBuildMessageHandler(future, null); final OSProcessHandler processHandler = launchBuildProcess(project, myListenPort, future.getRequestID(), true); @@ -1349,6 +1339,7 @@ public class BuildManager implements ApplicationComponent{ Disposer.register(project, new Disposable() { @Override public void dispose() { + cancelPreloadedBuilds(projectPath); myProjectDataMap.remove(projectPath); } }); @@ -1368,7 +1359,7 @@ public class BuildManager implements ApplicationComponent{ @Override public void projectClosing(Project project) { - cancelPreloadedBuilds(project); + cancelPreloadedBuilds(getProjectPath(project)); for (TaskFuture future : cancelAutoMakeTasks(project)) { future.waitFor(500, TimeUnit.MILLISECONDS); } @@ -1613,4 +1604,10 @@ public class BuildManager implements ApplicationComponent{ } } + private class CancelBuildSessionAction implements RequestFuture.CancelAction { + @Override + public void cancel(RequestFuture future) throws Exception { + myMessageDispatcher.cancelSession(future.getRequestID()); + } + } } diff --git a/java/compiler/impl/src/com/intellij/compiler/server/PreloadedProcessMessageHandler.java b/java/compiler/impl/src/com/intellij/compiler/server/PreloadedProcessMessageHandler.java index 5a8c3e28a1c6..2a328caabe22 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/PreloadedProcessMessageHandler.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/PreloadedProcessMessageHandler.java @@ -15,25 +15,14 @@ */ package com.intellij.compiler.server; -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; - /** * @author Eugene Zhuravlev * Date: 20-Oct-14 */ class PreloadedProcessMessageHandler extends DelegatingMessageHandler { - @NotNull - private final Project myProject; private volatile BuilderMessageHandler myDelegateHandler; - public PreloadedProcessMessageHandler(@NotNull Project project) { - myProject = project; - } - - @NotNull - public Project getProject() { - return myProject; + public PreloadedProcessMessageHandler() { } @Override diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java index faf69aaee937..8115aac74c79 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java @@ -1249,6 +1249,11 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { } } myResult = new ArrayInitializerEvaluator(evaluators); + if (!(expression.getParent() instanceof PsiNewExpression)) { + myResult = new NewArrayInstanceEvaluator(new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(type)), + null, + myResult); + } } @Nullable diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerParametersRunnerConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerParametersRunnerConfigurable.java index 2d07226a7229..59073f3cd373 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerParametersRunnerConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerParametersRunnerConfigurable.java @@ -51,7 +51,7 @@ public class GenericDebuggerParametersRunnerConfigurable extends SettingsEditor< myDebuggerSettings.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - ShowSettingsUtil.getInstance().showSettingsDialog(project, DebuggerConfigurable.DISPLAY_NAME); + ShowSettingsUtil.getInstance().showSettingsDialog(project, DebuggerConfigurable.class); if (myIsLocal) { setTransport(DebuggerSettings.getInstance().DEBUGGER_TRANSPORT); } diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java index 914df8b14a83..5ec0450b8db7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java @@ -63,6 +63,7 @@ class DebuggerSteppingConfigurable implements ConfigurableUi { @Override public void apply(@NotNull DebuggerSettings settings) { + mySteppingFilterEditor.stopEditing(); getSettingsTo(settings); } @@ -83,7 +84,6 @@ class DebuggerSteppingConfigurable implements ConfigurableUi { settings.EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ASK; } - mySteppingFilterEditor.stopEditing(); settings.setSteppingFilters(mySteppingFilterEditor.getFilters()); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspectionBase.java index e13f3e66a198..d2dfb1f5c6a8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspectionBase.java @@ -31,6 +31,8 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.*; import com.intellij.psi.controlFlow.*; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Processor; @@ -75,6 +77,19 @@ public class FieldCanBeLocalInspectionBase extends BaseJavaBatchLocalInspectionT for (final PsiField field : candidates) { if (usedFields.contains(field) && !hasImplicitReadOrWriteUsage(field, implicitUsageProviders)) { + if (!ReferencesSearch.search(field, new LocalSearchScope(aClass)).forEach(new Processor() { + @Override + public boolean process(PsiReference reference) { + final PsiElement element = reference.getElement(); + if (element instanceof PsiReferenceExpression) { + final PsiElement qualifier = ((PsiReferenceExpression)element).getQualifier(); + return qualifier == null || qualifier instanceof PsiThisExpression && ((PsiThisExpression)qualifier).getQualifier() == null; + } + return true; + } + })) { + continue; + } final String message = InspectionsBundle.message("inspection.field.can.be.local.problem.descriptor"); final ArrayList fixes = new ArrayList(); SpecialAnnotationsUtilBase.createAddToSpecialAnnotationFixes(field, new Processor() { diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/InvertIfConditionAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/InvertIfConditionAction.java index 9815601a16c9..6815ca94c9df 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/InvertIfConditionAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/InvertIfConditionAction.java @@ -158,8 +158,9 @@ public class InvertIfConditionAction extends PsiElementBaseIntentionAction { } private static PsiElement findCodeBlock(PsiIfStatement ifStatement) { - PsiElement e = PsiTreeUtil.getParentOfType(ifStatement, PsiMethod.class, PsiClassInitializer.class); + PsiElement e = PsiTreeUtil.getParentOfType(ifStatement, PsiMethod.class, PsiClassInitializer.class, PsiLambdaExpression.class); if (e instanceof PsiMethod) return ((PsiMethod) e).getBody(); + if (e instanceof PsiLambdaExpression) return ((PsiLambdaExpression)e).getBody(); if (e instanceof PsiClassInitializer) return ((PsiClassInitializer) e).getBody(); return null; } diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java index ef5544775adb..b01ca0a8039b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java @@ -15,14 +15,11 @@ */ package com.intellij.codeInspection.deadCode; -import com.intellij.codeInspection.GlobalInspectionContext; import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.codeInspection.ex.EntryPointsManager; +import com.intellij.codeInspection.ex.EntryPointsManagerImpl; import com.intellij.codeInspection.reference.EntryPoint; import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection; import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspectionBase; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; import com.intellij.ui.components.JBTabbedPane; import org.jetbrains.annotations.TestOnly; @@ -53,17 +50,6 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase return tabs; } - private Project guessProject() { - final GlobalInspectionContext context = getContext(); - Project project = context == null ? null : context.getProject(); - - if (project == null) { - Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); - project = openProjects.length == 0 ? ProjectManager.getInstance().getDefaultProject() : openProjects[0]; - } - return project; - } - private class OptionsPanel extends JPanel { private final JCheckBox myMainsCheckbox; private final JCheckBox myAppletToEntries; @@ -141,8 +127,7 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase gc.gridy++; add(myNonJavaCheckbox, gc); - Project project = guessProject(); - JButton configureAnnotations = EntryPointsManager.getInstance(project).createConfigureAnnotationsBtn(); + JButton configureAnnotations = EntryPointsManagerImpl.createConfigureAnnotationsButton(); gc.fill = GridBagConstraints.NONE; gc.gridy++; gc.insets.top = 10; diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java index 209f7ef827fb..2ef2dc12829b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java @@ -28,6 +28,7 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.ui.DialogWrapper; import org.jdom.Element; @@ -73,11 +74,15 @@ public class EntryPointsManagerImpl extends EntryPointsManagerBase implements Pe @Override public JButton createConfigureAnnotationsBtn() { + return createConfigureAnnotationsButton(); + } + + public static JButton createConfigureAnnotationsButton() { final JButton configureAnnotations = new JButton("Configure annotations..."); configureAnnotations.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - configureAnnotations(); + getInstance(ProjectUtil.guessCurrentProject(configureAnnotations)).configureAnnotations(); } }); return configureAnnotations; diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java index bb97f5cd78d5..9e1f28254b65 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedParameters/UnusedParametersInspection.java @@ -29,10 +29,10 @@ import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.EntryPointsManager; +import com.intellij.codeInspection.ex.EntryPointsManagerImpl; import com.intellij.codeInspection.reference.*; import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspectionBase; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.psi.search.PsiReferenceProcessor; @@ -234,8 +234,7 @@ public class UnusedParametersInspection extends GlobalJavaBatchInspectionTool { @Override public JComponent createOptionsPanel() { final JPanel panel = new JPanel(new GridBagLayout()); - Project project = ProjectUtil.guessCurrentProject(panel); - panel.add(EntryPointsManager.getInstance(project).createConfigureAnnotationsBtn(), + panel.add(EntryPointsManagerImpl.createConfigureAnnotationsButton(), new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); return panel; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java index 87a45bf8cdeb..e5ae3926e4ca 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java @@ -28,6 +28,8 @@ import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; import com.intellij.psi.search.searches.SuperMethodsSearch; import com.intellij.psi.util.*; import com.intellij.util.*; +import com.intellij.util.containers.ConcurrentFactoryMap; +import com.intellij.util.containers.FactoryMap; import gnu.trove.THashMap; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; @@ -43,7 +45,20 @@ public class PsiSuperMethodImplUtil { @NotNull @Override public Map fun(PsiClass dom) { - return buildMethodHierarchy(dom, PsiSubstitutor.EMPTY, true, new THashSet(), false); + return buildMethodHierarchy(dom, null, PsiSubstitutor.EMPTY, true, new THashSet(), false); + } + }); + private static final PsiCacheKey>, PsiClass> SIGNATURES_BY_NAME_KEY = PsiCacheKey + .create("SIGNATURES_BY_NAME_KEY", new Function>>() { + @Override + public FactoryMap> fun(final PsiClass psiClass) { + return new ConcurrentFactoryMap>() { + @Nullable + @Override + protected Map create(String methodName) { + return buildMethodHierarchy(psiClass, methodName, PsiSubstitutor.EMPTY, true, new THashSet(), false); + } + }; } }); @@ -112,6 +127,7 @@ public class PsiSuperMethodImplUtil { @NotNull private static Map buildMethodHierarchy(@NotNull PsiClass aClass, + @Nullable String nameHint, @NotNull PsiSubstitutor substitutor, final boolean includePrivates, @NotNull final Set visited, @@ -144,7 +160,7 @@ public class PsiSuperMethodImplUtil { }); PsiMethod[] methods = aClass.getMethods(); - if (aClass instanceof PsiClassImpl) { + if ((nameHint == null || "values".equals(nameHint)) && aClass instanceof PsiClassImpl) { final PsiMethod valuesMethod = ((PsiClassImpl)aClass).getValuesMethod(); if (valuesMethod != null) { methods = ArrayUtil.append(methods, valuesMethod); @@ -155,6 +171,7 @@ public class PsiSuperMethodImplUtil { if (!method.isValid()) { throw new PsiInvalidElementAccessException(method, "class.valid=" + aClass.isValid() + "; name=" + method.getName()); } + if (nameHint != null && !nameHint.equals(method.getName())) continue; if (!includePrivates && method.hasModifierProperty(PsiModifier.PRIVATE)) continue; final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, substitutor, isInRawContext); HierarchicalMethodSignatureImpl newH = new HierarchicalMethodSignatureImpl(signature); @@ -180,7 +197,7 @@ public class PsiSuperMethodImplUtil { PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superSubstitutor, substitutor, isInRawContext); final boolean isInRawContextSuper = (isInRawContext || PsiUtil.isRawSubstitutor(superClass, superSubstitutor)) && superClass.getTypeParameters().length != 0; - Map superResult = buildMethodHierarchy(superClass, finalSubstitutor, false, visited, isInRawContextSuper); + Map superResult = buildMethodHierarchy(superClass, nameHint, finalSubstitutor, false, visited, isInRawContextSuper); visited.remove(superClass); List> flattened = new ArrayList>(); @@ -366,7 +383,7 @@ public class PsiSuperMethodImplUtil { PsiClass aClass = method.getContainingClass(); HierarchicalMethodSignature result = null; if (aClass != null) { - result = getSignaturesMap(aClass).get(method.getSignature(PsiSubstitutor.EMPTY)); + result = SIGNATURES_BY_NAME_KEY.getValue(aClass).get(method.getName()).get(method.getSignature(PsiSubstitutor.EMPTY)); } if (result == null) { result = new HierarchicalMethodSignatureImpl((MethodSignatureBackedByPsiMethod)method.getSignature(PsiSubstitutor.EMPTY)); @@ -395,40 +412,14 @@ public class PsiSuperMethodImplUtil { if (!canHaveSuperMethod(method, true, false)) return false; - Map cachedMap = SIGNATURES_FOR_CLASS_KEY.getCachedValueOrNull(aClass); - if (cachedMap != null) { - HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); - if (signature != null) { - List superSignatures = signature.getSuperSignatures(); - for (HierarchicalMethodSignature superSignature : superSignatures) { - if (!superMethodProcessor.process(superSignature.getMethod())) return false; - } - return true; + Map cachedMap = SIGNATURES_BY_NAME_KEY.getValue(aClass).get(method.getName()); + HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); + if (signature != null) { + List superSignatures = signature.getSuperSignatures(); + for (HierarchicalMethodSignature superSignature : superSignatures) { + if (!superMethodProcessor.process(superSignature.getMethod())) return false; } } - - PsiClassType[] directSupers = aClass.getSuperTypes(); - for (PsiClassType directSuper : directSupers) { - PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics(); - if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) { - // generics - break; - } - PsiClass directSuperClass = resolveResult.getElement(); - if (directSuperClass == null) continue; - PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false); - for (PsiMethod candidate : candidates) { - if (PsiUtil.canBeOverriden(candidate)) { - if (!superMethodProcessor.process(candidate)) return false; - } - } - return true; - } - - List superSignatures = method.getHierarchicalMethodSignature().getSuperSignatures(); - for (HierarchicalMethodSignature superSignature : superSignatures) { - if (!superMethodProcessor.process(superSignature.getMethod())) return false; - } return true; } @@ -444,42 +435,10 @@ public class PsiSuperMethodImplUtil { if (!canHaveSuperMethod(method, true, false)) return false; - PsiMethod[] superMethods = null; - Map cachedMap = SIGNATURES_FOR_CLASS_KEY.getCachedValueOrNull(aClass); - if (cachedMap != null) { - HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); - if (signature != null) { - superMethods = MethodSignatureUtil.convertMethodSignaturesToMethods(signature.getSuperSignatures()); - } - } - if (superMethods == null) { - PsiClassType[] directSupers = aClass.getSuperTypes(); - List found = null; - boolean canceled = false; - for (PsiClassType directSuper : directSupers) { - PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics(); - if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) { - // generics - canceled = true; - break; - } - PsiClass directSuperClass = resolveResult.getElement(); - if (directSuperClass == null) continue; - PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false); - if (candidates.length != 0) { - if (found == null) found = new ArrayList(); - for (PsiMethod candidate : candidates) { - if (PsiUtil.canBeOverriden(candidate)) found.add(candidate); - } - } - } - superMethods = canceled ? null : found == null ? PsiMethod.EMPTY_ARRAY : found.toArray(new PsiMethod[found.size()]); - } - if (superMethods == null) { - superMethods = MethodSignatureUtil.convertMethodSignaturesToMethods(method.getHierarchicalMethodSignature().getSuperSignatures()); - } + Map cachedMap = SIGNATURES_BY_NAME_KEY.getValue(aClass).get(method.getName()); + HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); - for (PsiMethod superCandidate : superMethods) { + for (PsiMethod superCandidate : MethodSignatureUtil.convertMethodSignaturesToMethods(signature.getSuperSignatures())) { if (superMethod.equals(superCandidate) || isSuperMethodSmart(superCandidate, superMethod)) return true; } return false; diff --git a/java/java-tests/testData/codeInsight/invertIfCondition/afterInsideLambda.java b/java/java-tests/testData/codeInsight/invertIfCondition/afterInsideLambda.java new file mode 100644 index 000000000000..0c58356b054b --- /dev/null +++ b/java/java-tests/testData/codeInsight/invertIfCondition/afterInsideLambda.java @@ -0,0 +1,13 @@ +// "Invert If Condition" "true" +class A { + public void foo() { + Runnable r = () -> { + if (System.currentTimeMillis() <= 1) { + System.err.println("Elvis lives"); + } + else { + return; + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/invertIfCondition/beforeInsideLambda.java b/java/java-tests/testData/codeInsight/invertIfCondition/beforeInsideLambda.java new file mode 100644 index 000000000000..85aa03f9edac --- /dev/null +++ b/java/java-tests/testData/codeInsight/invertIfCondition/beforeInsideLambda.java @@ -0,0 +1,11 @@ +// "Invert If Condition" "true" +class A { + public void foo() { + Runnable r = () -> { + if (System.currentTimeMillis() > 1) { + return; + } + System.err.println("Elvis lives"); + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/expected.xml b/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/expected.xml new file mode 100644 index 000000000000..28a09cdef54c --- /dev/null +++ b/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/expected.xml @@ -0,0 +1,9 @@ + + + + Test.java + 3 + Field can be local + Field can be converted to a local variable + + diff --git a/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/src/Test.java b/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/src/Test.java new file mode 100644 index 000000000000..3ea480d779c9 --- /dev/null +++ b/java/java-tests/testData/inspection/fieldCanBeLocal/fieldReferencedFromAnotherObject/src/Test.java @@ -0,0 +1,15 @@ +class G { + private G foo; + private int bar; + + public G(final G gFoo) { + foo = gFoo; + bar = 1; + System.out.println(this.bar); + + G g = this; + while (g.foo != null) { + g = g.foo; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java index db303c699ddc..3470669e2dfe 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java @@ -39,6 +39,7 @@ public class FieldCanBeLocalTest extends InspectionTestCase { public void testFieldWithImmutableType() throws Exception {doTest();} public void testFieldUsedForWritingInLambda() throws Exception {doTest();} public void testStaticQualifiedFieldAccessForWriting() throws Exception {doTest();} + public void testFieldReferencedFromAnotherObject() throws Exception {doTest();} public void testIgnoreAnnotated() throws Exception { final FieldCanBeLocalInspection inspection = new FieldCanBeLocalInspection(); doTestConfigured(inspection); diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy new file mode 100644 index 000000000000..64492f94d62a --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy @@ -0,0 +1,305 @@ +/* + * 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.index +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.command.impl.CurrentEditorProvider +import com.intellij.openapi.command.impl.UndoManagerImpl +import com.intellij.openapi.command.undo.UndoManager +import com.intellij.openapi.editor.Document +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.fileEditor.FileEditor +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileTypes.PlainTextFileType +import com.intellij.openapi.util.Factory +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry +import com.intellij.psi.* +import com.intellij.psi.impl.PsiManagerEx +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.PsiSearchHelper +import com.intellij.testFramework.PlatformTestUtil +import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase +import com.intellij.util.indexing.MapIndexStorage +import com.intellij.util.indexing.StorageException +import com.intellij.util.io.* +import org.jetbrains.annotations.NotNull +/** + * @author Eugene Zhuravlev + * Date: Dec 12, 2007 + */ +public class IndexTest extends JavaCodeInsightFixtureTestCase { + @Override + protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception { + if ("testUndoToFileContentForUnsavedCommittedDocument".equals(getName())) { + super.invokeTestRunnable(runnable); + } else { + WriteCommandAction.runWriteCommandAction(getProject(), runnable); + } + } + + public void testUpdate() throws StorageException, IOException { + final File storageFile = FileUtil.createTempFile("indextest", "storage"); + final File metaIndexFile = FileUtil.createTempFile("indextest_inputs", "storage"); + final MapIndexStorage indexStorage = new MapIndexStorage(storageFile, new EnumeratorStringDescriptor(), new EnumeratorStringDescriptor(), 16 * 1024); + final StringIndex index = new StringIndex(indexStorage, new Factory>>() { + @Override + public PersistentHashMap> create() { + try { + return createMetaIndex(metaIndexFile); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + }); + + try { +// build index + index.update("com/ppp/a.java", "a b c d", null); + index.update("com/ppp/b.java", "a b g h", null); + index.update("com/ppp/c.java", "a z f", null); + index.update("com/ppp/d.java", "a a u y z", null); + index.update("com/ppp/e.java", "a n chj e c d", null); + + assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java"); + assertDataEquals(index.getFilesByWord("b"), "com/ppp/a.java", "com/ppp/b.java"); + assertDataEquals(index.getFilesByWord("c"), "com/ppp/a.java", "com/ppp/e.java"); + assertDataEquals(index.getFilesByWord("d"), "com/ppp/a.java", "com/ppp/e.java"); + assertDataEquals(index.getFilesByWord("g"), "com/ppp/b.java"); + assertDataEquals(index.getFilesByWord("h"), "com/ppp/b.java"); + assertDataEquals(index.getFilesByWord("z"), "com/ppp/c.java", "com/ppp/d.java"); + assertDataEquals(index.getFilesByWord("f"), "com/ppp/c.java"); + assertDataEquals(index.getFilesByWord("u"), "com/ppp/d.java"); + assertDataEquals(index.getFilesByWord("y"), "com/ppp/d.java"); + assertDataEquals(index.getFilesByWord("n"), "com/ppp/e.java"); + assertDataEquals(index.getFilesByWord("chj"), "com/ppp/e.java"); + assertDataEquals(index.getFilesByWord("e"), "com/ppp/e.java"); + + // update index + + index.update("com/ppp/d.java", "a u y z", "a a u y z"); + assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java"); + index.update("com/ppp/d.java", "u y z", "a u y z"); + assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/e.java"); + index.update("com/ppp/d.java", "a a a u y z", "u y z"); + assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java"); + + index.update("com/ppp/e.java", "a n chj e c d z", "a n chj e c d"); + assertDataEquals(index.getFilesByWord("z"), "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java"); + + index.update("com/ppp/b.java", null, "a b g h"); + assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java"); + assertDataEquals(index.getFilesByWord("b"), "com/ppp/a.java"); + assertDataEquals(index.getFilesByWord("g")); + assertDataEquals(index.getFilesByWord("h")); + } + finally { + indexStorage.close(); + FileUtil.delete(storageFile); + } + } + + private static PersistentHashMap> createMetaIndex(File metaIndexFile) throws IOException { + return new PersistentHashMap>(metaIndexFile, new EnumeratorIntegerDescriptor(), new DataExternalizer>() { + @Override + public void save(@NotNull DataOutput out, Collection value) throws IOException { + DataInputOutputUtil.writeINT(out, value.size()); + for (String key : value) { + out.writeUTF(key); + } + } + + @Override + public Collection read(@NotNull DataInput _in) throws IOException { + final int size = DataInputOutputUtil.readINT(_in); + final List list = new ArrayList(); + for (int idx = 0; idx < size; idx++) { + list.add(_in.readUTF()); + } + return list; + } + }); + } + + private static void assertDataEquals(List actual, T... expected) { + assertTrue(new HashSet(Arrays.asList(expected)).equals(new HashSet(actual))); + } + + public void testCollectedPsiWithChangedDocument() throws IOException { + final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile(); + + assertNotNull(findClass("Foo")); + PsiFile psiFile = getPsiManager().findFile(vFile); + assertNotNull(psiFile); + + Document document = FileDocumentManager.getInstance().getDocument(vFile); + document.deleteString(0, document.getTextLength()); + assertNotNull(findClass("Foo")); + + psiFile = null; + PlatformTestUtil.tryGcSoftlyReachableObjects(); + assertNull(getPsiManager().getFileManager().getCachedPsiFile(vFile)); + + PsiClass foo = findClass("Foo"); + assertNotNull(foo); + assertTrue(foo.isValid()); + assertEquals("class Foo {}", foo.getText()); + assertTrue(foo.isValid()); + + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + assertNull(findClass("Foo")); + } + + public void testCollectedPsiWithDocumentChangedCommittedAndChangedAgain() throws IOException { + final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile(); + + assertNotNull(findClass("Foo")); + PsiFile psiFile = getPsiManager().findFile(vFile); + assertNotNull(psiFile); + + Document document = FileDocumentManager.getInstance().getDocument(vFile); + document.deleteString(0, document.getTextLength()); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + document.insertString(0, " "); + //assertNotNull(myJavaFacade.findClass("Foo", scope)); + + psiFile = null; + PlatformTestUtil.tryGcSoftlyReachableObjects(); + assertNull(getPsiManager().getFileManager().getCachedPsiFile(vFile)); + + PsiClass foo = findClass("Foo"); + assertNull(foo); + } + + private PsiClass findClass(String name) { + return JavaPsiFacade.getInstance(getProject()).findClass(name, GlobalSearchScope.allScope(getProject())); + } + + public void testSavedUncommittedDocument() throws IOException { + final VirtualFile vFile = myFixture.addFileToProject("Foo.java", "").getVirtualFile(); + + assertNull(findClass("Foo")); + PsiFile psiFile = getPsiManager().findFile(vFile); + assertNotNull(psiFile); + + long count = getPsiManager().getModificationTracker().getModificationCount(); + + Document document = FileDocumentManager.getInstance().getDocument(vFile); + document.insertString(0, "class Foo {}"); + FileDocumentManager.getInstance().saveDocument(document); + + assertTrue(count == getPsiManager().getModificationTracker().getModificationCount()); + assertNull(findClass("Foo")); + + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + assertNotNull(findClass("Foo")); + assertNotNull(findClass("Foo").getText()); + // if Foo exists now, mod count should be different + assertTrue(count != getPsiManager().getModificationTracker().getModificationCount()); + } + + public void testSkipUnknownFileTypes() throws IOException { + final VirtualFile vFile = myFixture.addFileToProject("Foo.test", "Foo").getVirtualFile(); + assertEquals(PlainTextFileType.INSTANCE, vFile.getFileType()); + final PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(getProject()); + assertOneElement(helper.findFilesWithPlainTextWords("Foo")); + + final Document document = FileDocumentManager.getInstance().getDocument(vFile); + //todo should file type be changed silently without events? + //assertEquals(UnknownFileType.INSTANCE, vFile.getFileType()); + + final PsiFile file = PsiDocumentManager.getInstance(getProject()).getPsiFile(document); + assertInstanceOf(file, PsiPlainTextFile.class); + assertEquals("Foo", file.getText()); + + assertOneElement(helper.findFilesWithPlainTextWords("Foo")); + + WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() { + @Override + public void run() { + document.insertString(0, " "); + assertEquals("Foo", file.getText()); + assertOneElement(helper.findFilesWithPlainTextWords("Foo")); + + FileDocumentManager.getInstance().saveDocument(document); + assertEquals("Foo", file.getText()); + assertOneElement(helper.findFilesWithPlainTextWords("Foo")); + + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + assertEquals(" Foo", file.getText()); + assertOneElement(helper.findFilesWithPlainTextWords("Foo")); + } + }); + } + + public void testUndoToFileContentForUnsavedCommittedDocument() throws IOException { + final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile(); + ((VirtualFileSystemEntry)vFile).setModificationStamp(0); // as unchanged file + + final Document document = FileDocumentManager.getInstance().getDocument(vFile); + assertTrue(document != null && document.getModificationStamp() == 0); + assertNotNull(findClass("Foo")); + + WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() { + @Override + public void run() { + document.insertString(0, "import Bar;\n"); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + assertNotNull(findClass("Foo")); + } + }); + + final UndoManager undoManager = UndoManager.getInstance(getProject()); + final FileEditor selectedEditor = FileEditorManager.getInstance(getProject()).openFile(vFile, false)[0]; + ((UndoManagerImpl)undoManager).setEditorProvider(new CurrentEditorProvider() { + @Override + public FileEditor getCurrentEditor() { + return selectedEditor; + } + }); + + assertTrue(undoManager.isUndoAvailable(selectedEditor)); + FileDocumentManager.getInstance().saveDocument(document); + undoManager.undo(selectedEditor); + + assertNotNull(findClass("Foo")); + } + + public void "test changing a file without psi makes the document committed and updates index"() { + def psiFile = myFixture.addFileToProject("Foo.java", "class Foo {}") + def vFile = psiFile.virtualFile + def scope = GlobalSearchScope.allScope(project) + + FileDocumentManager.instance.getDocument(vFile).text = "import zoo.Zoo; class Foo1 {}" + assert PsiDocumentManager.getInstance(project).uncommittedDocuments + psiFile = null + + PlatformTestUtil.tryGcSoftlyReachableObjects() + + assert !((PsiManagerEx) psiManager).fileManager.getCachedPsiFile(vFile) + + FileDocumentManager.instance.saveAllDocuments() + + VfsUtil.saveText(vFile, "class Foo3 {}") + + assert !PsiDocumentManager.getInstance(project).uncommittedDocuments + + assert JavaPsiFacade.getInstance(project).findClass("Foo3", scope) + } + +} diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.java b/java/java-tests/testSrc/com/intellij/index/IndexTest.java deleted file mode 100644 index 93130e085e91..000000000000 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.java +++ /dev/null @@ -1,388 +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.intellij.index; - -import com.intellij.codeInsight.CodeInsightTestCase; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.command.impl.CurrentEditorProvider; -import com.intellij.openapi.command.impl.UndoManagerImpl; -import com.intellij.openapi.command.undo.UndoManager; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileEditor.FileEditor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileTypes.PlainTextFileType; -import com.intellij.openapi.util.Factory; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry; -import com.intellij.psi.*; -import com.intellij.psi.impl.PsiManagerEx; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.PsiSearchHelper; -import com.intellij.testFramework.PlatformTestUtil; -import com.intellij.testFramework.PsiTestUtil; -import com.intellij.testFramework.SkipSlowTestLocally; -import com.intellij.util.indexing.MapIndexStorage; -import com.intellij.util.indexing.StorageException; -import com.intellij.util.io.*; -import org.jetbrains.annotations.NotNull; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * @author Eugene Zhuravlev - * Date: Dec 12, 2007 - */ -@SkipSlowTestLocally -public class IndexTest extends CodeInsightTestCase { - - public void testUpdate() throws StorageException, IOException { - final File storageFile = FileUtil.createTempFile("indextest", "storage"); - final File metaIndexFile = FileUtil.createTempFile("indextest_inputs", "storage"); - final MapIndexStorage indexStorage = new MapIndexStorage(storageFile, new EnumeratorStringDescriptor(), new EnumeratorStringDescriptor(), 16 * 1024); - final StringIndex index = new StringIndex(indexStorage, new Factory>>() { - @Override - public PersistentHashMap> create() { - try { - return createMetaIndex(metaIndexFile); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - }); - - try { -// build index - index.update("com/ppp/a.java", "a b c d", null); - index.update("com/ppp/b.java", "a b g h", null); - index.update("com/ppp/c.java", "a z f", null); - index.update("com/ppp/d.java", "a a u y z", null); - index.update("com/ppp/e.java", "a n chj e c d", null); - - assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java"); - assertDataEquals(index.getFilesByWord("b"), "com/ppp/a.java", "com/ppp/b.java"); - assertDataEquals(index.getFilesByWord("c"), "com/ppp/a.java", "com/ppp/e.java"); - assertDataEquals(index.getFilesByWord("d"), "com/ppp/a.java", "com/ppp/e.java"); - assertDataEquals(index.getFilesByWord("g"), "com/ppp/b.java"); - assertDataEquals(index.getFilesByWord("h"), "com/ppp/b.java"); - assertDataEquals(index.getFilesByWord("z"), "com/ppp/c.java", "com/ppp/d.java"); - assertDataEquals(index.getFilesByWord("f"), "com/ppp/c.java"); - assertDataEquals(index.getFilesByWord("u"), "com/ppp/d.java"); - assertDataEquals(index.getFilesByWord("y"), "com/ppp/d.java"); - assertDataEquals(index.getFilesByWord("n"), "com/ppp/e.java"); - assertDataEquals(index.getFilesByWord("chj"), "com/ppp/e.java"); - assertDataEquals(index.getFilesByWord("e"), "com/ppp/e.java"); - - // update index - - index.update("com/ppp/d.java", "a u y z", "a a u y z"); - assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java"); - index.update("com/ppp/d.java", "u y z", "a u y z"); - assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/e.java"); - index.update("com/ppp/d.java", "a a a u y z", "u y z"); - assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java"); - - index.update("com/ppp/e.java", "a n chj e c d z", "a n chj e c d"); - assertDataEquals(index.getFilesByWord("z"), "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java"); - - index.update("com/ppp/b.java", null, "a b g h"); - assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java"); - assertDataEquals(index.getFilesByWord("b"), "com/ppp/a.java"); - assertDataEquals(index.getFilesByWord("g")); - assertDataEquals(index.getFilesByWord("h")); - } - finally { - indexStorage.close(); - FileUtil.delete(storageFile); - } - } - - private PersistentHashMap> createMetaIndex(File metaIndexFile) throws IOException { - return new PersistentHashMap>(metaIndexFile, new EnumeratorIntegerDescriptor(), new DataExternalizer>() { - @Override - public void save(@NotNull DataOutput out, Collection value) throws IOException { - DataInputOutputUtil.writeINT(out, value.size()); - for (String key : value) { - out.writeUTF(key); - } - } - - @Override - public Collection read(@NotNull DataInput in) throws IOException { - final int size = DataInputOutputUtil.readINT(in); - final List list = new ArrayList(); - for (int idx = 0; idx < size; idx++) { - list.add(in.readUTF()); - } - return list; - } - }); - } - - /* - public void testStubIndexUnsavedDocumentsIndexing() throws IncorrectOperationException, IOException, StorageException { - IdeaTestUtil.registerExtension(StubIndexExtension.EP_NAME, new TextStubIndexExtension(), getTestRootDisposable()); - IdeaTestUtil.registerExtension(StubIndexExtension.EP_NAME, new ClassNameStubIndexExtension(), getTestRootDisposable()); - FileTypeManager.getInstance().registerFileType(TestFileType.INSTANCE, "fff"); - final FFFLangParserDefinition parserDefinition = new FFFLangParserDefinition(); - LanguageParserDefinitions.INSTANCE.addExplicitExtension(FFFLanguage.INSTANCE, parserDefinition); - - final TestStubElementType stubType = new TestStubElementType(); - SerializationManager.getInstance().registerSerializer(TestStubElement.class, stubType); - - final File fffFile = new File(FileUtil.createTempDirectory("testing", "stubindex"), "MyClass.fff"); - fffFile.createNewFile(); - - final VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(fffFile); - - assertNotNull(vFile); - assertEquals(TestFileType.INSTANCE, vFile.getFileType()); - - try { - final MockPsiFile psiFile = new MockPsiFile(vFile, MockPsiManager.getInstance(myProject)); - - final MockPsiClass cls = new MockPsiClass("com.company.MyClass"); - psiFile.add(cls); - - final MockPsiMethod aaaMethod = new MockPsiMethod("aaa"); - cls.addMethod(aaaMethod); - final MockPsiMethod bbbMethod = new MockPsiMethod("bbb"); - cls.addMethod(bbbMethod); - - final PsiFileStubImpl fileStub = new PsiFileStubImpl(psiFile); - final TestStubElement clsStub = stubType.createStub(cls, fileStub); - stubType.createStub(aaaMethod, clsStub); - stubType.createStub(bbbMethod, clsStub); - - final ByteArrayOutputStream arrayStream = new ByteArrayOutputStream(); - SerializationManager.getInstance().serialize(fileStub, new DataOutputStream(arrayStream)); - - final FileBasedIndex fbi = FileBasedIndex.getInstance(); - final UpdatableIndex stubUpdatingIndex = fbi.getIndex(StubUpdatingIndex.INDEX_ID); - final MemoryIndexStorage storage = (MemoryIndexStorage)((MapReduceIndex)stubUpdatingIndex).getStorage(); - - // initial - final int fileId = FileBasedIndex.getFileId(vFile); - final byte[] bytes = arrayStream.toByteArray(); - stubUpdatingIndex.update(fileId, new FileContent(vFile, bytes), null); - - final ValueContainer data = stubUpdatingIndex.getData(fileId); - final List trees = data.toValueList(); - - final SerializedStubTree tree = assertOneElement(trees); - - assertTrue(Comparing.equal(bytes, tree.getBytes())); - - final StubElement deserialized = tree.getStub(); - } - finally { - LanguageParserDefinitions.INSTANCE.removeExplicitExtension(FFFLanguage.INSTANCE, parserDefinition); - } - - } - */ - - private static void assertDataEquals(List actual, T... expected) { - assertTrue(new HashSet(Arrays.asList(expected)).equals(new HashSet(actual))); - } - - public void testCollectedPsiWithChangedDocument() throws IOException { - VirtualFile dir = getVirtualFile(createTempDirectory()); - PsiTestUtil.addSourceContentToRoots(myModule, dir); - - final VirtualFile vFile = createChildData(dir, "Foo.java"); - VfsUtil.saveText(vFile, "class Foo {}"); - - final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); - assertNotNull(myJavaFacade.findClass("Foo", scope)); - WriteCommandAction.runWriteCommandAction(null, new Runnable() { - @Override - public void run() { - PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(vFile); - assertNotNull(psiFile); - - Document document = FileDocumentManager.getInstance().getDocument(vFile); - document.deleteString(0, document.getTextLength()); - assertNotNull(myJavaFacade.findClass("Foo", scope)); - - psiFile = null; - PlatformTestUtil.tryGcSoftlyReachableObjects(); - assertNull(((PsiManagerEx)PsiManager.getInstance(getProject())).getFileManager().getCachedPsiFile(vFile)); - - PsiClass foo = myJavaFacade.findClass("Foo", scope); - assertNotNull(foo); - assertTrue(foo.isValid()); - assertEquals("class Foo {}", foo.getText()); - assertTrue(foo.isValid()); - - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNull(myJavaFacade.findClass("Foo", scope)); - } - }); - } - - public void _testCollectedPsiWithDocumentChangedCommittedAndChangedAgain() throws IOException { - VirtualFile dir = getVirtualFile(createTempDirectory()); - PsiTestUtil.addSourceContentToRoots(myModule, dir); - - final VirtualFile vFile = createChildData(dir, "Foo.java"); - VfsUtil.saveText(vFile, "class Foo {}"); - - final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); - assertNotNull(myJavaFacade.findClass("Foo", scope)); - WriteCommandAction.runWriteCommandAction(null, new Runnable() { - @Override - public void run() { - PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(vFile); - assertNotNull(psiFile); - - Document document = FileDocumentManager.getInstance().getDocument(vFile); - document.deleteString(0, document.getTextLength()); - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - document.insertString(0, " "); - //assertNotNull(myJavaFacade.findClass("Foo", scope)); - - psiFile = null; - PlatformTestUtil.tryGcSoftlyReachableObjects(); - assertNull(((PsiManagerEx)PsiManager.getInstance(getProject())).getFileManager().getCachedPsiFile(vFile)); - - PsiClass foo = myJavaFacade.findClass("Foo", scope); - assertNotNull(foo); - assertTrue(foo.isValid()); - assertEquals("class Foo {}", foo.getText()); - assertTrue(foo.isValid()); - - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNull(myJavaFacade.findClass("Foo", scope)); - } - }); - } - - public void testSavedUncommittedDocument() throws IOException { - VirtualFile dir = getVirtualFile(createTempDirectory()); - PsiTestUtil.addSourceContentToRoots(myModule, dir); - - final VirtualFile vFile = createChildData(dir, "Foo.java"); - VfsUtil.saveText(vFile, ""); - - final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); - assertNull(myJavaFacade.findClass("Foo", scope)); - WriteCommandAction.runWriteCommandAction(null, new Runnable() { - @Override - public void run() { - PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(vFile); - assertNotNull(psiFile); - - long count = PsiManager.getInstance(myProject).getModificationTracker().getModificationCount(); - - Document document = FileDocumentManager.getInstance().getDocument(vFile); - document.insertString(0, "class Foo {}"); - FileDocumentManager.getInstance().saveDocument(document); - - assertTrue(count == PsiManager.getInstance(myProject).getModificationTracker().getModificationCount()); - assertNull(myJavaFacade.findClass("Foo", scope)); - - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNotNull(myJavaFacade.findClass("Foo", scope)); - assertNotNull(myJavaFacade.findClass("Foo", scope).getText()); - // if Foo exists now, mod count should be different - assertTrue(count != PsiManager.getInstance(myProject).getModificationTracker().getModificationCount()); - } - }); - } - - public void testSkipUnknownFileTypes() throws IOException { - VirtualFile dir = getVirtualFile(createTempDirectory()); - PsiTestUtil.addSourceContentToRoots(myModule, dir); - - final VirtualFile vFile = createChildData(dir, "Foo.test"); - VfsUtil.saveText(vFile, "Foo"); - assertEquals(PlainTextFileType.INSTANCE, vFile.getFileType()); - assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); - - final Document document = FileDocumentManager.getInstance().getDocument(vFile); - //todo should file type be changed silently without events? - //assertEquals(UnknownFileType.INSTANCE, vFile.getFileType()); - - final PsiFile file = getPsiFile(document); - assertInstanceOf(file, PsiPlainTextFile.class); - assertEquals("Foo", file.getText()); - - assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); - - WriteCommandAction.runWriteCommandAction(myProject, new Runnable() { - @Override - public void run() { - document.insertString(0, " "); - assertEquals("Foo", file.getText()); - assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); - - FileDocumentManager.getInstance().saveDocument(document); - assertEquals("Foo", file.getText()); - assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); - - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertEquals(" Foo", file.getText()); - assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); - } - }); - } - - public void testUndoToFileContentForUnsavedCommittedDocument() throws IOException { - VirtualFile dir = getVirtualFile(createTempDirectory()); - PsiTestUtil.addSourceContentToRoots(myModule, dir); - - final VirtualFile vFile = createChildData(dir, "Foo.java"); - VfsUtil.saveText(vFile, "class Foo {}"); - ((VirtualFileSystemEntry)vFile).setModificationStamp(0); // as unchanged file - - final Document document = FileDocumentManager.getInstance().getDocument(vFile); - assertTrue(document != null && document.getModificationStamp() == 0); - final GlobalSearchScope scope = GlobalSearchScope.projectScope(myProject); - assertNotNull(myJavaFacade.findClass("Foo", scope)); - - WriteCommandAction.runWriteCommandAction(myProject, new Runnable() { - @Override - public void run() { - document.insertString(0, "import Bar;\n"); - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNotNull(myJavaFacade.findClass("Foo", scope)); - } - }); - - final UndoManager undoManager = UndoManager.getInstance(getProject()); - final FileEditor selectedEditor = FileEditorManager.getInstance(myProject).openFile(vFile, false)[0]; - ((UndoManagerImpl)undoManager).setEditorProvider(new CurrentEditorProvider() { - @Override - public FileEditor getCurrentEditor() { - return selectedEditor; - } - }); - - assertTrue(undoManager.isUndoAvailable(selectedEditor)); - FileDocumentManager.getInstance().saveDocument(document); - undoManager.undo(selectedEditor); - - assertNotNull(myJavaFacade.findClass("Foo", scope)); - } -} diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTestGenerator.scala b/java/java-tests/testSrc/com/intellij/index/IndexTestGenerator.scala index ae6727bd9928..98d0268adfba 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTestGenerator.scala +++ b/java/java-tests/testSrc/com/intellij/index/IndexTestGenerator.scala @@ -25,8 +25,11 @@ import org.scalacheck._ import scala.collection.JavaConversions._ /** - * Run this class to generate randomized tests for IDEA VFS/document/PSI/index subsystem interaction using ScalaCheck. - * When a test fails, a test method code (in Groovy) is printed which should be copied to a normal test class and debugged there. + * Run this class to generate randomized tests for IDEA VFS/document/PSI/index subsystem interaction using ScalaCheck.

+ * + * When a test fails, a test method code (in Groovy) is printed which should be copied to a normal test class (IndexTest) + * and debugged there.

+ * * The generated test may contain some excessive declarations and checks that should be corrected manually. * After the fix, that generated test should be renamed according to the underlying issue it found and committed to the repository. * diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/strategies/ExprMatchingStrategy.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/strategies/ExprMatchingStrategy.java index c892badb85be..a1bebac82a42 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/strategies/ExprMatchingStrategy.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/strategies/ExprMatchingStrategy.java @@ -6,6 +6,27 @@ import com.intellij.psi.*; * Expression matching strategy */ public class ExprMatchingStrategy extends MatchingStrategyBase { + + @Override public void visitAnnotation(final PsiAnnotation annotation) { + result = true; + } + + @Override public void visitAnnotationParameterList(final PsiAnnotationParameterList list) { + result = true; + } + + @Override public void visitModifierList(final PsiModifierList list) { + result = true; + } + + @Override public void visitNameValuePair(final PsiNameValuePair pair) { + result = true; + } + + @Override public void visitAnnotationArrayInitializer(PsiArrayInitializerMemberValue initializer) { + result = true; + } + @Override public void visitExpression(final PsiExpression expr) { result = true; } diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java index 6262638088f6..22a514a3903a 100644 --- a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java @@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiElementFactory; import com.intellij.psi.PsiManager; +import com.intellij.psi.impl.PsiManagerEx; import com.intellij.testFramework.IdeaTestCase; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; @@ -105,8 +106,8 @@ public abstract class JavaCodeInsightFixtureTestCase extends UsefulTestCase{ return myFixture.getProject(); } - protected PsiManager getPsiManager() { - return PsiManager.getInstance(getProject()); + protected PsiManagerEx getPsiManager() { + return (PsiManagerEx)PsiManager.getInstance(getProject()); } public PsiElementFactory getElementFactory() { diff --git a/platform/analysis-api/src/com/intellij/codeInspection/ex/EntryPointsManager.java b/platform/analysis-api/src/com/intellij/codeInspection/ex/EntryPointsManager.java index 14a9002d109c..02f3f3cfac1a 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/ex/EntryPointsManager.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/ex/EntryPointsManager.java @@ -29,6 +29,8 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; public abstract class EntryPointsManager implements Disposable { public static EntryPointsManager getInstance(Project project) { @@ -50,6 +52,10 @@ public abstract class EntryPointsManager implements Disposable { public abstract void configureAnnotations(); + /** + * {@link com.intellij.codeInspection.ex.EntryPointsManagerImpl#createConfigureAnnotationsButton()} should be used instead + */ + @Deprecated public abstract JButton createConfigureAnnotationsBtn(); public abstract boolean isEntryPoint(@NotNull PsiElement element); diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java index 70577a37ff24..9709dcd8592d 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java @@ -75,7 +75,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, @TestOnly public static boolean INIT_INSPECTIONS = false; private static Map ourMergers = null; - final InspectionToolRegistrar myRegistrar; + private final InspectionToolRegistrar myRegistrar; @NotNull private final Map myDeinstalledInspectionsSettings; private final ExternalInfo myExternalInfo = new ExternalInfo(); @@ -342,9 +342,9 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, inspectionElement.setAttribute(CLASS_TAG, toolName); toolList.writeExternal(inspectionElement); - if (areSettingsMerged(toolName, inspectionElement)) continue; - - element.addContent(inspectionElement); + if (!areSettingsMerged(toolName, inspectionElement)) { + element.addContent(inspectionElement); + } } else { element.addContent(toolElement.clone()); @@ -378,13 +378,12 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, if (mainToolId != null) { InspectionToolWrapper dependentEntryWrapper = getInspectionTool(mainToolId, project); - if (dependentEntryWrapper != null) { - if (!dependentEntries.add(dependentEntryWrapper)) { - collectDependentInspections(dependentEntryWrapper, dependentEntries, project); - } + if (dependentEntryWrapper == null) { + LOG.error("Can't find main tool: '" + mainToolId+"' which was specified in "+toolWrapper); + return; } - else { - LOG.error("Can't find main tool: " + mainToolId); + if (!dependentEntries.add(dependentEntryWrapper)) { + collectDependentInspections(dependentEntryWrapper, dependentEntries, project); } } } @@ -1015,6 +1014,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, } } + @Override @NotNull public String toString() { return mySource == null ? getName() : getName() + " (copy)"; diff --git a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java index d2a7a9aefdbc..d05b11e47de1 100644 --- a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java +++ b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java @@ -109,6 +109,15 @@ public abstract class PsiDocumentManager { @NotNull public abstract CharSequence getLastCommittedText(@NotNull Document document); + /** + * @return for uncommitted documents, the last stamp before the document change: the same stamp that current PSI should have. + * For committed documents, just their stamp. + * + * @see Document#getModificationStamp() + * @see FileViewProvider#getModificationStamp() + */ + public abstract long getLastCommittedStamp(@NotNull Document document); + /** * Returns the list of documents which have been modified but not committed. * diff --git a/platform/core-impl/src/com/intellij/extapi/psi/ASTDelegatePsiElement.java b/platform/core-impl/src/com/intellij/extapi/psi/ASTDelegatePsiElement.java index fbcb7afc0731..6cbb68219ef2 100644 --- a/platform/core-impl/src/com/intellij/extapi/psi/ASTDelegatePsiElement.java +++ b/platform/core-impl/src/com/intellij/extapi/psi/ASTDelegatePsiElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,10 @@ import com.intellij.psi.impl.PsiElementBase; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; -import com.intellij.psi.impl.source.tree.*; +import com.intellij.psi.impl.source.tree.ChangeUtil; +import com.intellij.psi.impl.source.tree.CompositeElement; +import com.intellij.psi.impl.source.tree.SharedImplUtil; +import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiUtilCore; @@ -334,9 +337,9 @@ public abstract class ASTDelegatePsiElement extends PsiElementBase { CheckUtil.checkWritable(this); ((ASTDelegatePsiElement)parent).deleteChildInternal(getNode()); } - else if (parent instanceof CompositePsiElement) { + else if (parent instanceof CompositeElement) { CheckUtil.checkWritable(this); - ((CompositePsiElement)parent).deleteChildInternal(getNode()); + ((CompositeElement)parent).deleteChildInternal(getNode()); } else if (parent instanceof PsiFile) { CheckUtil.checkWritable(this); diff --git a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java index df1bfa77a451..ef244898400d 100644 --- a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java @@ -277,7 +277,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements MutablePicoContainer container = myPicoContainer; if (container == null || myDisposeCompleted) { ProgressManager.checkCanceled(); - throw new AssertionError("Already disposed"); + throw new AssertionError("Already disposed: "+toString()); } return container; } diff --git a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java index 63a7f205c11c..6899460bf235 100644 --- a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java +++ b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java @@ -165,7 +165,6 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi @Override public void beforeContentsSynchronized() { - unsetPsiContent(); } @Override @@ -501,7 +500,20 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi @Override public long getModificationStamp() { - return getVirtualFile().getModificationStamp(); + final VirtualFile virtualFile = getVirtualFile(); + if (virtualFile instanceof LightVirtualFile) { + Document doc = getCachedDocument(); + if (doc != null) return getLastCommittedStamp(doc); + return virtualFile.getModificationStamp(); + } + + final Document document = getDocument(); + if (document == null) { + return virtualFile.getModificationStamp(); + } + else { + return getLastCommittedStamp(document); + } } @NonNls @@ -514,6 +526,9 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi private CharSequence getLastCommittedText(Document document) { return PsiDocumentManager.getInstance(myManager.getProject()).getLastCommittedText(document); } + private long getLastCommittedStamp(Document document) { + return PsiDocumentManager.getInstance(myManager.getProject()).getLastCommittedStamp(document); + } private class DocumentContent implements Content { @NonNls @@ -534,7 +549,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi @Override public long getModificationStamp() { Document document = com.intellij.reference.SoftReference.dereference(myDocument); - if (document != null) return document.getModificationStamp(); + if (document != null) return getLastCommittedStamp(document); return myVirtualFile.getModificationStamp(); } } diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java index 9bd52662a5b3..bdc83f8098cb 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java @@ -34,6 +34,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -67,7 +68,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen private final PsiManager myPsiManager; private final DocumentCommitProcessor myDocumentCommitProcessor; protected final Set myUncommittedDocuments = ContainerUtil.newConcurrentSet(); - private final Map myLastCommittedTexts = ContainerUtil.newConcurrentMap(); + private final Map> myLastCommittedTexts = ContainerUtil.newConcurrentMap(); private volatile boolean myIsCommitInProgress; private final PsiToDocumentSynchronizer mySynchronizer; @@ -558,8 +559,14 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen @Override @NotNull public CharSequence getLastCommittedText(@NotNull Document document) { - CharSequence text = myLastCommittedTexts.get(document); - return text != null ? text : document.getImmutableCharSequence(); + Pair pair = myLastCommittedTexts.get(document); + return pair != null ? pair.first : document.getImmutableCharSequence(); + } + + @Override + public long getLastCommittedStamp(@NotNull Document document) { + Pair pair = myLastCommittedTexts.get(document); + return pair != null ? pair.second : document.getModificationStamp(); } @Override @@ -595,7 +602,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen public void beforeDocumentChange(@NotNull DocumentEvent event) { final Document document = event.getDocument(); if (!(document instanceof DocumentWindow) && !myLastCommittedTexts.containsKey(document)) { - myLastCommittedTexts.put(document, document.getImmutableCharSequence()); + myLastCommittedTexts.put(document, Pair.create(document.getImmutableCharSequence(), document.getModificationStamp())); } VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document); @@ -713,14 +720,16 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen } public void handleCommitWithoutPsi(@NotNull Document document) { - final CharSequence prevText = myLastCommittedTexts.remove(document); - if (prevText == null) { + final Pair prevPair = myLastCommittedTexts.remove(document); + if (prevPair == null) { return; } if (!myProject.isInitialized() || myProject.isDisposed()) { return; } + + myUncommittedDocuments.remove(document); VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document); if (virtualFile == null || !FileIndexFacade.getInstance(myProject).isInContent(virtualFile)) { @@ -738,7 +747,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen public void run() { psiFile.getViewProvider().beforeContentsSynchronized(); synchronized (PsiLock.LOCK) { - final int oldLength = prevText.length(); + final int oldLength = prevPair.first.length(); PsiManagerImpl manager = (PsiManagerImpl)psiFile.getManager(); BlockSupportImpl.sendBeforeChildrenChangeEvent(manager, psiFile, true); BlockSupportImpl.sendBeforeChildrenChangeEvent(manager, psiFile, false); diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index 12300a2bcf45..cc0be29ae7e3 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -389,6 +389,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF DebugUtil.finishPsiModification(); } } + myViewProvider.contentsSynchronized(); } private void clearStub(@NotNull String reason) { diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java b/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java index f8bfc611ce55..c0b7d3352bb4 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java @@ -163,21 +163,28 @@ public class CompositeElement extends TreeElement { startFind: while (true) { TreeElement child = element.getFirstChildNode(); + TreeElement lastChild = element.getLastChildNode(); + boolean fwd = lastChild == null || (lastChild.getStartOffset() + lastChild.getTextLength() - child.getStartOffset()) / 2 > offset; + if (!fwd) { + child = lastChild; + offset = element.getTextLength() - offset; + } while (child != null) { final int textLength = child.getTextLength(); - if (textLength > offset) { + if (textLength > offset || !fwd && textLength >= offset) { if (child instanceof LeafElement) { if (child instanceof ForeignLeafPsiElement) { - child = child.getTreeNext(); + child = fwd ? child.getTreeNext() : child.getTreePrev(); continue; } return (LeafElement)child; } + offset = fwd ? offset : child.getTextLength() - offset; element = child; continue startFind; } offset -= textLength; - child = child.getTreeNext(); + child = fwd ? child.getTreeNext() : child.getTreePrev(); } return null; } diff --git a/platform/duplicates-analysis/src/com/intellij/dupLocator/treeHash/NodeSpecificHasherBase.java b/platform/duplicates-analysis/src/com/intellij/dupLocator/treeHash/NodeSpecificHasherBase.java index ef2e92fad8be..7b7553e0293d 100644 --- a/platform/duplicates-analysis/src/com/intellij/dupLocator/treeHash/NodeSpecificHasherBase.java +++ b/platform/duplicates-analysis/src/com/intellij/dupLocator/treeHash/NodeSpecificHasherBase.java @@ -7,8 +7,11 @@ import com.intellij.dupLocator.iterators.SiblingNodeIterator; import com.intellij.dupLocator.util.DuplocatorUtil; import com.intellij.dupLocator.util.NodeFilter; import com.intellij.lang.Language; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiErrorElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.impl.source.tree.LeafElement; import com.intellij.psi.tree.IElementType; @@ -131,7 +134,14 @@ public class NodeSpecificHasherBase extends NodeSpecificHasher { @Override public void visitNode(@NotNull PsiElement node) { - final Language language = node.getLanguage(); + Language language = null; + if (node instanceof PsiFile) { + FileType fileType = ((PsiFile)node).getFileType(); + if (fileType instanceof LanguageFileType) { + language = ((LanguageFileType)fileType).getLanguage(); + } + } + if (language == null) language = node.getLanguage(); if ((myForIndexing || mySettings.SELECTED_PROFILES.contains(language.getDisplayName())) && myDuplicatesProfile.isMyLanguage(language)) { diff --git a/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java b/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java index cc01782b7541..0dac0d7d3b0c 100644 --- a/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java +++ b/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java @@ -115,16 +115,21 @@ public class ProjectUtil { } @NotNull - public static Project guessCurrentProject(JComponent component) { + public static Project guessCurrentProject(@Nullable JComponent component) { Project project = null; - Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); - if (openProjects.length > 0) project = openProjects[0]; - if (project == null) { - DataContext dataContext = component == null ? DataManager.getInstance().getDataContext() : DataManager.getInstance().getDataContext(component); - project = CommonDataKeys.PROJECT.getData(dataContext); + if (component != null) { + project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(component)); } if (project == null) { - project = ProjectManager.getInstance().getDefaultProject(); + Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); + if (openProjects.length > 0) project = openProjects[0]; + if (project == null) { + DataContext dataContext = DataManager.getInstance().getDataContext(); + project = CommonDataKeys.PROJECT.getData(dataContext); + } + if (project == null) { + project = ProjectManager.getInstance().getDefaultProject(); + } } return project; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java index fbab8ef759aa..a9b3cff485fc 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java @@ -38,9 +38,11 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.impl.source.tree.injected.Place; import com.intellij.psi.tree.IElementType; +import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; @@ -80,6 +82,7 @@ public class InjectedGeneralHighlightingPass extends GeneralHighlightingPass imp final List outside = new ArrayList(); List insideRanges = new ArrayList(); List outsideRanges = new ArrayList(); + //TODO: this thing is just called TWICE with same arguments eating CPU on huge files :( Divider.divideInsideAndOutside(myFile, myStartOffset, myEndOffset, myPriorityRange, inside, insideRanges, outside, outsideRanges, false, FILE_FILTER); @@ -148,7 +151,7 @@ public class InjectedGeneralHighlightingPass extends GeneralHighlightingPass imp final Set outInjected = new THashSet(); List injected = InjectedLanguageUtil.getCachedInjectedDocuments(myFile); - Collection hosts = new THashSet(elements1.size() + elements2.size() + injected.size()); + final Collection hosts = new THashSet(elements1.size() + elements2.size() + injected.size()); //rehighlight all injected PSI regardless the range, //since change in one place can lead to invalidation of injected PSI in (completely) other place. @@ -165,8 +168,10 @@ public class InjectedGeneralHighlightingPass extends GeneralHighlightingPass imp hosts.add(context); } } - hosts.addAll(elements1); - hosts.addAll(elements2); + InjectedLanguageManagerImpl injectedLanguageManager = InjectedLanguageManagerImpl.getInstanceImpl(myProject); + Processor collectInjectableProcessor = new CommonProcessors.CollectProcessor(hosts); + injectedLanguageManager.processInjectableElements(elements1, collectInjectableProcessor); + injectedLanguageManager.processInjectableElements(elements2, collectInjectableProcessor); final PsiLanguageInjectionHost.InjectedPsiVisitor visitor = new PsiLanguageInjectionHost.InjectedPsiVisitor() { @Override diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java index 19a247f4a4a1..530e979d1db0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java @@ -48,9 +48,11 @@ import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.util.Function; import com.intellij.util.FunctionUtil; +import com.intellij.util.Processor; import gnu.trove.THashSet; import gnu.trove.TIntObjectHashMap; import org.jetbrains.annotations.NotNull; @@ -201,7 +203,7 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM public static void collectLineMarkersForInjected(@NotNull final List result, @NotNull List elements, @NotNull final LineMarkersProcessor processor, - @NotNull PsiFile file, + @NotNull final PsiFile file, @NotNull final ProgressIndicator progress) { final InjectedLanguageManager manager = InjectedLanguageManager.getInstance(file.getProject()); final List injectedMarkers = new ArrayList(); @@ -213,9 +215,13 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM injectedFiles.add(injectedPsi); } }; - for (int i = 0, size = elements.size(); i < size; ++i) { - InjectedLanguageUtil.enumerate(elements.get(i), file, false, collectingVisitor); - } + InjectedLanguageManagerImpl.getInstanceImpl(file.getProject()).processInjectableElements(elements, new Processor() { + @Override + public boolean process(PsiElement element) { + InjectedLanguageUtil.enumerate(element, file, false, collectingVisitor); + return true; + } + }); for (PsiFile injectedPsi : injectedFiles) { final Project project = injectedPsi.getProject(); Document document = PsiDocumentManager.getInstance(project).getCachedDocument(injectedPsi); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/fillParagraph/ParagraphFillHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/fillParagraph/ParagraphFillHandler.java index 3aeefefd55ec..930148b05e5c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/fillParagraph/ParagraphFillHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/fillParagraph/ParagraphFillHandler.java @@ -4,6 +4,7 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.UnfairTextRange; import com.intellij.openapi.util.text.CharFilter; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; @@ -82,7 +83,7 @@ public class ParagraphFillHandler { private TextRange getTextRange(@NotNull final PsiElement element, @NotNull final Editor editor) { int startOffset = getStartOffset(element, editor); int endOffset = getEndOffset(element, editor); - return TextRange.create(startOffset, endOffset); + return new UnfairTextRange(startOffset, endOffset); } private int getStartOffset(@NotNull final PsiElement element, @NotNull final Editor editor) { @@ -105,7 +106,7 @@ public class ParagraphFillHandler { } lineNumber -= 1; } - final int lineStartOffset = document.getLineStartOffset(lineNumber); + final int lineStartOffset = lineNumber == document.getLineNumber(elementTextOffset) ? elementTextOffset : document.getLineStartOffset(lineNumber); final String lineText = document .getText(TextRange.create(lineStartOffset, document.getLineEndOffset(lineNumber))); int shift = StringUtil.findFirst(lineText, CharFilter.NOT_WHITESPACE_FILTER); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java index 400127979dd5..6abcb85c8318 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java @@ -60,13 +60,13 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.ui.content.*; +import com.intellij.util.ConcurrencyUtil; import com.intellij.util.Processor; import com.intellij.util.SequentialModalProgressTask; import com.intellij.util.TripleFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.ui.UIUtil; -import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jdom.Document; import org.jdom.Element; @@ -78,7 +78,9 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; +import java.lang.reflect.Constructor; import java.util.*; +import java.util.concurrent.ConcurrentMap; public class GlobalInspectionContextImpl extends GlobalInspectionContextBase implements GlobalInspectionContext { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.GlobalInspectionContextImpl"); @@ -592,7 +594,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp } } - private final Map myPresentationMap = new THashMap(); + private final ConcurrentMap myPresentationMap = ContainerUtil.newConcurrentMap(); @NotNull public InspectionToolPresentation getPresentation(@NotNull InspectionToolWrapper toolWrapper) { InspectionToolPresentation presentation = myPresentationMap.get(toolWrapper); @@ -601,12 +603,15 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp DefaultInspectionToolPresentation.class.getName()); try { - presentation = (InspectionToolPresentation)Class.forName(presentationClass).getConstructor(InspectionToolWrapper.class, GlobalInspectionContextImpl.class).newInstance(toolWrapper, this); + Constructor constructor = + Class.forName(presentationClass).getConstructor(InspectionToolWrapper.class, GlobalInspectionContextImpl.class); + presentation = (InspectionToolPresentation)constructor.newInstance(toolWrapper, this); } catch (Exception e) { LOG.error(e); + throw new RuntimeException(e); } - myPresentationMap.put(toolWrapper, presentation); + presentation = ConcurrencyUtil.cacheOrGet(myPresentationMap, toolWrapper, presentation); } return presentation; } diff --git a/platform/lang-impl/src/com/intellij/ide/util/MemberChooser.java b/platform/lang-impl/src/com/intellij/ide/util/MemberChooser.java index 2ced07e8e3a6..2addc59170b4 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/MemberChooser.java +++ b/platform/lang-impl/src/com/intellij/ide/util/MemberChooser.java @@ -27,6 +27,8 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; +import com.intellij.psi.PsiCompiledElement; +import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.ui.*; @@ -904,8 +906,11 @@ public class MemberChooser extends DialogWrapper implemen @Override public int compare(ElementNode n1, ElementNode n2) { if (n1.getDelegate() instanceof ClassMemberWithElement && n2.getDelegate() instanceof ClassMemberWithElement) { - return ((ClassMemberWithElement)n1.getDelegate()).getElement().getTextOffset() - - ((ClassMemberWithElement)n2.getDelegate()).getElement().getTextOffset(); + PsiElement element1 = ((ClassMemberWithElement)n1.getDelegate()).getElement(); + PsiElement element2 = ((ClassMemberWithElement)n2.getDelegate()).getElement(); + if (!(element1 instanceof PsiCompiledElement) && !(element2 instanceof PsiCompiledElement)) { + return element1.getTextOffset() - element2.getTextOffset(); + } } return n1.getOrder() - n2.getOrder(); } diff --git a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java index 2729a15e40db..d70b45f60f2a 100644 --- a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java +++ b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeFactory.java @@ -51,10 +51,7 @@ public class EnforcedPlainTextFileTypeFactory extends FileTypeFactory { @Override public boolean isMyFileType(@NotNull VirtualFile file) { - if (isMarkedAsPlainText(file)) { - return true; - } - return false; + return isMarkedAsPlainText(file); } @NotNull diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java index 34b8f9b06ef8..b2c7d1411fdb 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java @@ -228,6 +228,14 @@ public class InjectedLanguageManagerImpl extends InjectedLanguageManager impleme private final Set myManualInjectors = Collections.synchronizedSet(new LinkedHashSet()); private volatile ClassMapCachingNulls cachedInjectors; + public void processInjectableElements(Collection in, Processor processor) { + ClassMapCachingNulls map = getInjectorMap(); + for (PsiElement element : in) { + if (map.get(element.getClass()) != null) + processor.process(element); + } + } + private ClassMapCachingNulls getInjectorMap() { ClassMapCachingNulls cached = cachedInjectors; if (cached != null) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java index 5ed96453c85e..96f318b3e72b 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java @@ -307,7 +307,7 @@ public class InjectedLanguageUtil { MultiHostRegistrarImpl registrar = null; PsiElement current = element; nextParent: - while (current != null && current != hostPsiFile) { + while (current != null && current != hostPsiFile && !(current instanceof PsiDirectory)) { ProgressManager.checkCanceled(); if ("EL".equals(current.getLanguage().getID())) break; ParameterizedCachedValue data = current.getUserData(INJECTED_PSI); diff --git a/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java b/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java index 2cb330c71114..d01aa1c06faa 100644 --- a/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java +++ b/platform/lang-impl/src/com/intellij/ui/DeferredIconImpl.java @@ -22,10 +22,15 @@ package com.intellij.ui; import com.intellij.concurrency.Job; import com.intellij.concurrency.JobLauncher; import com.intellij.ide.PowerSaveMode; +import com.intellij.openapi.application.ApplicationAdapter; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.project.IndexNotReadyException; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.tabs.impl.TabLabel; import com.intellij.util.Alarm; @@ -119,18 +124,43 @@ public class DeferredIconImpl implements DeferredIcon { final long startTime = System.currentTimeMillis(); if (myNeedReadAction) { - if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(new Runnable() { + final ProgressIndicatorBase progress = new ProgressIndicatorBase(); + final ApplicationAdapter listener = new ApplicationAdapter() { + @Override + public void beforeWriteActionStart(Object action) { + progress.cancel(); + } + }; + ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { - IconDeferrerImpl.evaluateDeferred(evalRunnable); - if (myAutoUpdatable) { - myLastCalcTime = System.currentTimeMillis(); - myLastTimeSpent = myLastCalcTime - startTime; - } + ApplicationManager.getApplication().addApplicationListener(listener); } - })) { - myIsScheduled = false; - return; + }, ModalityState.any()); + try { + final Ref cancelled = new Ref(); + ProgressManager.getInstance().runProcess(new Runnable() { + @Override + public void run() { + if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(new Runnable() { + @Override + public void run() { + IconDeferrerImpl.evaluateDeferred(evalRunnable); + if (myAutoUpdatable) { + myLastCalcTime = System.currentTimeMillis(); + myLastTimeSpent = myLastCalcTime - startTime; + } + } + })) { + myIsScheduled = false; + cancelled.set(Boolean.TRUE); + } + } + }, progress); + if (cancelled.get() == Boolean.TRUE) return; + } catch(ProcessCanceledException e) {} + finally { + ApplicationManager.getApplication().removeApplicationListener(listener); } } else { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 989ff0b07105..d8dd50719cf6 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -1349,9 +1349,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { boolean allDocsProcessed = true; try { for (Document document : documents) { - if (psiBasedIndex && project != null && PsiDocumentManager.getInstance(project).isUncommited(document)) { - continue; - } allDocsProcessed &= indexUnsavedDocument(document, indexId, project, filter, restrictedFile); ProgressManager.checkCanceled(); } @@ -1451,7 +1448,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { return false; } - final PsiFile dominantContentFile = findDominantPsiForDocument(document, project); + final PsiFile dominantContentFile = project == null ? null : findLatestKnownPsiForUncomittedDocument(document, project); final DocumentContent content; if (dominantContentFile != null && dominantContentFile.getViewProvider().getModificationStamp() != document.getModificationStamp()) { @@ -1461,7 +1458,9 @@ public class FileBasedIndexImpl extends FileBasedIndex { content = new AuthenticContent(document); } - final long currentDocStamp = content.getModificationStamp(); + boolean psiBasedIndex = myPsiDependentIndices.contains(requestedIndexId); + + final long currentDocStamp = psiBasedIndex ? PsiDocumentManager.getInstance(project).getLastCommittedStamp(document) : content.getModificationStamp(); final long previousDocStamp = myLastIndexedDocStamps.getAndSet(document, requestedIndexId, currentDocStamp); if (currentDocStamp != previousDocStamp) { final CharSequence contentText = content.getText(); @@ -1509,14 +1508,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { private final TaskQueue myContentlessIndicesUpdateQueue = new TaskQueue(10000); - @Nullable - private PsiFile findDominantPsiForDocument(@NotNull Document document, @Nullable Project project) { - PsiFile psiFile = myTransactionMap.get(document); - if (psiFile != null) return psiFile; - - return project == null ? null : findLatestKnownPsiForUncomittedDocument(document, project); - } - private final StorageGuard myStorageLock = new StorageGuard(); private volatile boolean myPreviousDataBufferingState; private final Object myBufferingStateUpdateLock = new Object(); diff --git a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java index 8273f9dd3463..d429f14c97d9 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java @@ -1176,9 +1176,7 @@ public abstract class DialogWrapper { } protected void init() { - if (!SwingUtilities.isEventDispatchThread()) { - LOG.error("Dialog must be init in EDT only: "+Thread.currentThread()); - } + ensureEventDispatchThread(); myErrorText = new ErrorText(); myErrorText.setVisible(false); @@ -1197,7 +1195,7 @@ public abstract class DialogWrapper { final CustomShortcutSet sc = new CustomShortcutSet(SHOW_OPTION_KEYSTROKE); final AnAction toggleShowOptions = new AnAction() { @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { expandNextOptionButton(); } }; @@ -1548,7 +1546,7 @@ public abstract class DialogWrapper { * @throws IllegalStateException if the dialog is invoked not on the event dispatch thread */ public void show() { - showAndGetOk(); + invokeShow(); } public boolean showAndGet() { @@ -1559,16 +1557,23 @@ public abstract class DialogWrapper { /** * You need this method ONLY for NON-MODAL dialogs. Otherwise, use {@link #show()} or {@link #showAndGet()}. * - * @return result callback + * @return result callback which set to "Done" on dialog close, and then its {@code getResult()} will contain {@code isOK()} */ @NotNull public AsyncResult showAndGetOk() { + if (isModal()) { + throw new IllegalStateException("The showAndGetOk() method is for modeless dialogs only"); + } + return invokeShow(); + } + + @NotNull + private AsyncResult invokeShow() { final AsyncResult result = new AsyncResult(); ensureEventDispatchThread(); registerKeyboardShortcuts(); - final Disposable uiParent = Disposer.get("ui"); if (uiParent != null) { // may be null if no app yet (license agreement) Disposer.register(uiParent, myDisposable); // ensure everything is disposed on app quit @@ -1600,7 +1605,6 @@ public abstract class DialogWrapper { } private void registerKeyboardShortcuts() { - final JRootPane rootPane = getRootPane(); if (rootPane == null) return; @@ -2010,7 +2014,7 @@ public abstract class DialogWrapper { */ private static void ensureEventDispatchThread() { if (!EventQueue.isDispatchThread()) { - throw new IllegalStateException("The DialogWrapper can be used only on event dispatch thread."); + throw new IllegalStateException("The DialogWrapper can be used only in event dispatch thread. Current thread: "+Thread.currentThread()); } } @@ -2121,7 +2125,7 @@ public abstract class DialogWrapper { return true; } - public void setValidationInfo(@Nullable ValidationInfo info) { + private void setValidationInfo(@Nullable ValidationInfo info) { myInfo = info; } } diff --git a/platform/platform-api/src/com/intellij/openapi/wm/IdeGlassPaneUtil.java b/platform/platform-api/src/com/intellij/openapi/wm/IdeGlassPaneUtil.java index 10d49e44ac48..d5985d9fe731 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/IdeGlassPaneUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/IdeGlassPaneUtil.java @@ -18,6 +18,7 @@ package com.intellij.openapi.wm; import com.intellij.openapi.Disposable; import com.intellij.openapi.ui.Painter; +import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Disposer; import com.intellij.util.ui.update.Activatable; import com.intellij.util.ui.update.UiNotifyConnector; @@ -70,6 +71,10 @@ public class IdeGlassPaneUtil { public static boolean canBePreprocessed(MouseEvent e) { Component c = SwingUtilities.getDeepestComponentAt(e.getComponent(), e.getX(), e.getY()); + if (JBPopupFactory.getInstance().getParentBalloonFor(c) != null) { + return false; + } + if (c instanceof IdeGlassPane.TopComponent) { return ((IdeGlassPane.TopComponent)c).canBePreprocessed(e); } diff --git a/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java b/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java index 853a9724d63d..6964d66d4ef0 100644 --- a/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java +++ b/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java @@ -190,16 +190,16 @@ public abstract class ToolbarDecorator implements CommonActionsPanel.ListenerFac return setToolbarBorder(new CustomLineBorder(top, left, bottom, right)); } - public ToolbarDecorator addExtraAction(AnActionButton action) { - if (action != null) { - myExtraActions.add(action); - } + public ToolbarDecorator addExtraAction(@NotNull AnActionButton action) { + myExtraActions.add(action); return this; } public ToolbarDecorator addExtraActions(AnActionButton... actions) { for (AnActionButton action : actions) { - addExtraAction(action); + if (action != null) { + addExtraAction(action); + } } return this; } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java b/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java index a8b9809cf65e..f7f14547e8aa 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java @@ -125,23 +125,13 @@ public class ShowSettingsUtilImpl extends ShowSettingsUtil { ConfigurableGroup[] groups = getConfigurableGroups(project, true); - Configurable config = findByClass(getConfigurables(groups, true), configurableClass); + Configurable config = new ConfigurableVisitor.ByType(configurableClass).find(groups); assert config != null : "Cannot find configurable: " + configurableClass.getName(); getDialog(project, groups, config).show(); } - @Nullable - private static Configurable findByClass(Configurable[] configurables, Class configurableClass) { - for (Configurable configurable : configurables) { - if (configurableClass.isInstance(configurable)) { - return configurable; - } - } - return null; - } - @Override public void showSettingsDialog(@Nullable final Project project, @NotNull final String nameToSelect) { ConfigurableGroup[] groups = getConfigurableGroups(project, true); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/BorderEffect.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/BorderEffect.java index 8f578d2f1cf0..8f7e6ffa4d94 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/BorderEffect.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/BorderEffect.java @@ -131,12 +131,13 @@ public class BorderEffect { int startX = startPoint.x; int startY = startPoint.y; int endX = endPoint.x; + int lineHeight = editor.getLineHeight(); if (height == 0) { int width = endX == startX ? 1 : endX - startX - 1; if (effectType == EffectType.ROUNDED_BOX) { - UIUtil.drawRectPickedOut((Graphics2D)g, startX, startY, width, editor.getLineHeight() - 1); + UIUtil.drawRectPickedOut((Graphics2D)g, startX, startY, width, lineHeight - 1); } else { - g.drawRect(startX, startY, width, editor.getLineHeight() - 1); + g.drawRect(startX, startY, width, lineHeight - 1); } return; } @@ -145,12 +146,12 @@ public class BorderEffect { border.verticalRel(height - 1); border.horizontalTo(endX); if (endX > 0) { - border.verticalRel(editor.getLineHeight()); + border.verticalRel(lineHeight); border.horizontalTo(0); border.verticalRel(-height + 1); } - else { - border.verticalTo(startY + editor.getLineHeight() - 1); + else if (height > lineHeight) { + border.verticalRel(-height + lineHeight + 1); } border.horizontalTo(startX); border.verticalTo(startY); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java index ca6de1b8c65f..b66cd66eaf77 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java @@ -525,10 +525,9 @@ public class CaretImpl extends UserDataHolderBase implements Caret { else { logicalPositionToUse = new LogicalPosition(line, column); } - setCurrentLogicalCaret(logicalPositionToUse); - final int offset = myEditor.logicalPositionToOffset(myLogicalCaret); + final int offset = myEditor.logicalPositionToOffset(logicalPositionToUse); if (debugBuffer != null) { - debugBuffer.append("Resulting logical position to use: ").append(myLogicalCaret).append(". It's mapped to offset ").append(offset).append("\n"); + debugBuffer.append("Resulting logical position to use: ").append(logicalPositionToUse).append(". It's mapped to offset ").append(offset).append("\n"); } FoldRegion collapsedAt = myEditor.getFoldingModel().getCollapsedRegionAtOffset(offset); @@ -554,8 +553,10 @@ public class CaretImpl extends UserDataHolderBase implements Caret { finally { mySkipChangeRequests = false; } + logicalPositionToUse = logicalPositionToUse.visualPositionAware ? logicalPositionToUse.withoutVisualPositionInfo() : logicalPositionToUse; } + setCurrentLogicalCaret(logicalPositionToUse); setLastColumnNumber(myLogicalCaret.column); myDesiredSelectionStartColumn = myDesiredSelectionEndColumn = -1; myVisibleCaret = myEditor.logicalToVisualPosition(myLogicalCaret); @@ -748,8 +749,8 @@ public class CaretImpl extends UserDataHolderBase implements Caret { } } - private void assertIsDispatchThread() { - myEditor.assertIsDispatchThread(); + private static void assertIsDispatchThread() { + EditorImpl.assertIsDispatchThread(); } private void validateCallContext() { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java index e4653693ac9c..a72366df3b1e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java @@ -46,6 +46,7 @@ import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.ProperTextRange; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ex.ToolWindowManagerEx; @@ -442,9 +443,10 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark errorIconBounds.y = (bounds.height - errorIconBounds.height) / 2 - 1; try { - g.setColor(getEditor().getColorsScheme().getDefaultBackground()); - g.fillRect(0, 0, bounds.width, bounds.height); - + if (!transparent()) { + g.setColor(getEditor().getColorsScheme().getDefaultBackground()); + g.fillRect(0, 0, bounds.width, bounds.height); + } if (myErrorStripeRenderer != null) { myErrorStripeRenderer.paint(this, g, errorIconBounds); } @@ -459,6 +461,10 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark return STRIPE_BUTTON_PREFERRED_SIZE; } } + + private boolean transparent() { + return Registry.is("editor.transparent.scrollbar", false); + } private class MyErrorPanel extends ButtonlessScrollBarUI implements MouseMotionListener, MouseListener, MouseWheelListener, UISettingsListener { private PopupHandler myHandler; @@ -478,7 +484,7 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark @Override public boolean alwaysShowTrack() { - if (scrollbar.getOrientation() == Adjustable.VERTICAL) return true; + if (scrollbar.getOrientation() == Adjustable.VERTICAL) return !transparent(); return super.alwaysShowTrack(); } @@ -568,6 +574,16 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark return super.getThickness() + myMinMarkHeight - 1 + fix; } + @Override + protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) { + if (transparent()) { + doPaintTrack(g, c, trackBounds); + } + else { + super.paintTrack(g, c, trackBounds); + } + } + @Override protected void doPaintTrack(Graphics g, JComponent c, Rectangle bounds) { if (isMacScrollbarHiddenAndDistractionFreeEnabled()) { @@ -607,6 +623,7 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark } private void paintTrackBasement(Graphics g, Rectangle bounds) { + if (transparent()) return; g.setColor(EditorColorsManager.getInstance().getGlobalScheme().getDefaultBackground()); g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java index b339d670989f..fa89bb14960a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java @@ -28,7 +28,7 @@ import java.util.*; * User: cdr */ abstract class FoldRegionsTree { - @NotNull private CachedData myCachedData = new CachedData(); + @NotNull private volatile CachedData myCachedData = new CachedData(); //sorted using RangeMarker.BY_START_OFFSET comparator //i.e., first by start offset, then, if start offsets are equal, by end offset diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java index 781a7c4e419d..ef62fecea783 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java @@ -43,6 +43,7 @@ import com.intellij.ui.tabs.UiDecorator; import com.intellij.util.SmartList; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -268,6 +269,7 @@ public abstract class EditorComposite implements Disposable { * @return preferred focused component inside myEditor composite. Composite uses FocusWatcher to * track focus movement inside the myEditor. */ + @Nullable public JComponent getPreferredFocusedComponent(){ if (mySelectedEditor == null) return null; diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java index 91dfb648e49b..0537781bde07 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java @@ -554,14 +554,11 @@ public class EditorWindow { public void requestFocus(boolean forced) { if (myTabbedPane != null) { myTabbedPane.requestFocus(forced); - } else { + } + else { EditorWithProviderComposite editor = getSelectedEditor(); - if (editor != null) { - JComponent toFocus = editor.getPreferredFocusedComponent(); - IdeFocusManager.findInstanceByComponent(toFocus).requestFocus(toFocus, forced); - } else { - IdeFocusManager.findInstanceByComponent(myPanel).requestFocus(myPanel, forced); - } + JComponent preferred = editor == null ? null : editor.getPreferredFocusedComponent(); + IdeFocusManager.findInstanceByComponent(preferred == null ? myPanel : preferred).requestFocus(myPanel, forced); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java index 9b1fd384dfa3..8ccfaf2faac3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java @@ -77,9 +77,11 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME private static final int VERSION = 11; private static final Key FILE_TYPE_KEY = Key.create("FILE_TYPE_KEY"); + // cached auto-detected file type. If the file was auto-detected as plain text or binary + // then the value is null and autoDetectedAsText, autoDetectedAsBinary and autoDetectWasRun sets are used instead. private static final Key DETECTED_FROM_CONTENT_FILE_TYPE_KEY = Key.create("DETECTED_FROM_CONTENT_FILE_TYPE_KEY"); private static final int DETECT_BUFFER_SIZE = 8192; // the number of bytes to read from the file to feed to the file type detector - private boolean RE_DETECT_ASYNC = !ApplicationManager.getApplication().isUnitTestMode(); + private static boolean RE_DETECT_ASYNC = !ApplicationManager.getApplication().isUnitTestMode(); private final Set myDefaultTypes = new THashSet(); private final List mySpecialFileTypes = new ArrayList(); @@ -257,6 +259,9 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME } }); files.remove(null); + if (toLog()) { + System.out.println("F: VFS events: " + events); + } if (!files.isEmpty() && RE_DETECT_ASYNC) { reDetectQueue.offer(files); } @@ -264,6 +269,10 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME }); } + private static boolean toLog() { + return RE_DETECT_ASYNC && ApplicationManager.getApplication().isUnitTestMode(); + } + private final TransferToPooledThreadQueue> reDetectQueue = new TransferToPooledThreadQueue>("File type re-detect", Conditions.alwaysFalse(), -1, new Processor>() { @Override public boolean process(Collection files) { @@ -284,12 +293,20 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME private void reDetect(@NotNull Collection files) { final List changed = new ArrayList(); for (VirtualFile file : files) { - if (wasAutoDetectedBefore(file) && isDetectable(file)) { + boolean shouldRedetect = wasAutoDetectedBefore(file) && isDetectable(file); + if (toLog()) { + System.out.println("F: Redetect file: " + file.getName() + "; shouldRedetect: " + shouldRedetect); + } + if (shouldRedetect) { FileType before = file.getFileType(); FileType after = detectFromContent(file); + if (toLog()) { + System.out.println("F: After redetect file: " + file.getName() + "; before: " + before.getName() + "; after: " + after.getName()+"; now getFileType()="+file.getFileType().getName()); + } + if (before != after) { changed.add(file); - LOG.debug(file+" type was re-detected. Was: "+before+"; now: "+after); + LOG.debug(file+" type was re-detected. Was: "+before.getName()+"; now: "+after.getName()); } } } @@ -392,6 +409,9 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME public static void cacheFileType(@NotNull VirtualFile file, @Nullable FileType fileType) { file.putUserData(FILE_TYPE_KEY, fileType); + if (toLog()) { + System.out.println("F: Cached file type for "+file.getName()+" to "+(fileType == null ? null : fileType.getName())); + } } @Override @@ -409,12 +429,20 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME for (int i = 0; i < mySpecialFileTypes.size(); i++) { FileTypeIdentifiableByVirtualFile type = mySpecialFileTypes.get(i); if (type.isMyFileType(file)) { + if (toLog()) { + System.out.println("F: Special file type for "+file.getName()+"; type: "+type.getName()); + } return type; } } fileType = getFileTypeByFileName(file.getNameSequence()); - if (fileType != UnknownFileType.INSTANCE) return fileType; + if (fileType != UnknownFileType.INSTANCE) { + if (toLog()) { + System.out.println("F: By name file type for "+file.getName()+"; type: "+fileType.getName()); + } + return fileType; + } if (!(file instanceof StubVirtualFile)) { fileType = getOrDetectFromContent(file); @@ -430,8 +458,13 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME int id = ((VirtualFileWithId)file).getId(); if (id < 0) return UnknownFileType.INSTANCE; if (autoDetectWasRun.get(id)) { - return autoDetectedAsText.get(id) ? FileTypes.PLAIN_TEXT : autoDetectedAsBinary.get(id) ? UnknownFileType.INSTANCE : - ObjectUtils.notNull(file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY), FileTypes.PLAIN_TEXT); + FileType type = autoDetectedAsText.get(id) ? FileTypes.PLAIN_TEXT : + autoDetectedAsBinary.get(id) ? UnknownFileType.INSTANCE : + ObjectUtils.notNull(file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY), FileTypes.PLAIN_TEXT); + if (toLog()) { + System.out.println("F: getFileType("+file.getName()+") = "+type.getName()); + } + return type; } boolean wasDetectedAsText = false; boolean wasDetectedAsBinary = false; @@ -465,6 +498,10 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME fileType = detectFromContent(file); } + if (toLog()) { + System.out.println("F: getFileType after detect run("+file.getName()+") = "+fileType.getName()); + } + return fileType; } @@ -501,6 +538,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME autoDetectedAsText.set(id, wasAutodetectedAsText); autoDetectedAsBinary.set(id, wasAutodetectedAsBinary); if (wasAutodetectedAsText || wasAutodetectedAsBinary) { + file.putUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY, null); return; } } @@ -535,9 +573,8 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME long start = System.currentTimeMillis(); try { final InputStream inputStream = ((FileSystemInterface)file.getFileSystem()).getInputStream(file); - final Ref result; + final Ref result = new Ref(UnknownFileType.INSTANCE); try { - result = new Ref(UnknownFileType.INSTANCE); FileUtil.processFirstBytes(inputStream, DETECT_BUFFER_SIZE, new Processor() { @Override public boolean process(ByteSequence byteSequence) { @@ -574,6 +611,9 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME inputStream.close(); } FileType fileType = result.get(); + if (toLog()) { + System.out.println("F: Redetect run for file: " + file.getName() + "; result: "+fileType.getName()); + } if (LOG.isDebugEnabled()) { LOG.debug(file + "; type=" + fileType.getDescription() + "; " + counterAutoDetect); diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java index 03ed0c82fd3b..9b91979fd22e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsDialog.java @@ -41,7 +41,7 @@ public final class SettingsDialog extends DialogWrapper implements DataProvider private boolean myApplyButtonNeeded; private boolean myResetButtonNeeded; - public SettingsDialog(Project project, @NotNull String key, @NotNull Configurable configurable, boolean showApplyButton) { + public SettingsDialog(Project project, String key, @NotNull Configurable configurable, boolean showApplyButton) { super(project, true); myDimensionServiceKey = key; myEditor = new ConfigurableEditor(myDisposable, configurable); @@ -49,7 +49,7 @@ public final class SettingsDialog extends DialogWrapper implements DataProvider init(configurable); } - public SettingsDialog(@NotNull Component parent, @NotNull String key, @NotNull Configurable configurable, boolean showApplyButton) { + public SettingsDialog(@NotNull Component parent, String key, @NotNull Configurable configurable, boolean showApplyButton) { super(parent, true); myDimensionServiceKey = key; myEditor = new ConfigurableEditor(myDisposable, configurable); diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/impl/ProgressManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/progress/impl/ProgressManagerImpl.java index 878e60099b50..51f14f8e2bd9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/impl/ProgressManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/progress/impl/ProgressManagerImpl.java @@ -56,7 +56,7 @@ import java.util.concurrent.atomic.AtomicReference; public class ProgressManagerImpl extends ProgressManager implements Disposable { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.impl.ProgressManagerImpl"); - public static final int CHECK_CANCELED_DELAY_MILLIS = 10; + static final int CHECK_CANCELED_DELAY_MILLIS = 10; private final AtomicInteger myCurrentUnsafeProgressCount = new AtomicInteger(0); private final AtomicInteger myCurrentModalProgressCount = new AtomicInteger(0); @@ -321,19 +321,17 @@ public class ProgressManagerImpl extends ProgressManager implements Disposable { Set threads = threadsUnderIndicator.get(indicator); if (threads != null) { for (Thread thread : threads) { - ProgressIndicator currentIndicator = getCurrentIndicator(thread); - boolean underCancelledIndicator = currentIndicator == indicator; - - if (!underCancelledIndicator && currentIndicator instanceof WrappedProgressIndicator) { - while(currentIndicator instanceof WrappedProgressIndicator) { - ProgressIndicator originalProgressIndicator = ((WrappedProgressIndicator)currentIndicator).getOriginalProgressIndicator(); - if (originalProgressIndicator == indicator) { - underCancelledIndicator = true; - break; - } - currentIndicator = originalProgressIndicator; + boolean underCancelledIndicator = false; + for (ProgressIndicator currentIndicator = getCurrentIndicator(thread); + currentIndicator != null; + currentIndicator = currentIndicator instanceof WrappedProgressIndicator ? + ((WrappedProgressIndicator)currentIndicator).getOriginalProgressIndicator() : null) { + if (currentIndicator == indicator) { + underCancelledIndicator = true; + break; } } + if (underCancelledIndicator) { threadsUnderCanceledIndicator.add(thread); } diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java b/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java index c6e037e5d30e..0b1789faf66d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java @@ -218,6 +218,8 @@ public class FrameWrapper implements Disposable, DataProvider { myStatusBar = null; } + frame.dispose(); + myDisposed = true; } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java b/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java index 2bff2a10d5cd..d8414ddc37ed 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/ex/ToolWindowManagerEx.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.wm.ex; +import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.wm.ToolWindowAnchor; @@ -35,6 +36,7 @@ public abstract class ToolWindowManagerEx extends ToolWindowManager { } public abstract void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l); + public abstract void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l, @NotNull Disposable parentDisposable); public abstract void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener l); /** diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java index 5fa360235cb2..24e04e100369 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowHeadlessManagerImpl.java @@ -217,6 +217,10 @@ public class ToolWindowHeadlessManagerImpl extends ToolWindowManagerEx { } + @Override + public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l, @NotNull Disposable parentDisposable) { + } + @Override public void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener l) { } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index 8acebb5b5bfd..598d13fcb830 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -566,6 +566,11 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements myDispatcher.addListener(l); } + @Override + public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l, @NotNull Disposable parentDisposable) { + myDispatcher.addListener(l, parentDisposable); + } + @Override public void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener l) { myDispatcher.removeListener(l); diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 76985ad77362..6f20a456c4c7 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -18,6 +18,7 @@ package com.intellij.ui; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.DataManager; import com.intellij.ide.ui.UISettings; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -25,6 +26,7 @@ import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; @@ -65,6 +67,7 @@ public abstract class SpeedSearchBase extends SpeedSear private boolean myClearSearchOnNavigateNoMatch = false; @NonNls protected static final String ENTERED_PREFIX_PROPERTY_NAME = "enteredPrefix"; + private Disposable myListenerDisposable; public SpeedSearchBase(Comp component) { myComponent = component; @@ -522,10 +525,9 @@ public abstract class SpeedSearchBase extends SpeedSear myPopupLayeredPane.validate(); myPopupLayeredPane.repaint(); myPopupLayeredPane = null; - - if (project != null) { - ((ToolWindowManagerEx)ToolWindowManager.getInstance(project)).removeToolWindowManagerListener(myWindowManagerListener); - } + + Disposer.dispose(myListenerDisposable); + myListenerDisposable = null; } else if (searchPopup != null) { FeatureUsageTracker.getInstance().triggerFeatureUsed("ui.tree.speedsearch"); @@ -543,7 +545,9 @@ public abstract class SpeedSearchBase extends SpeedSear if (mySearchPopup == null || !myComponent.isDisplayable()) return; if (project != null) { - ((ToolWindowManagerEx)ToolWindowManager.getInstance(project)).addToolWindowManagerListener(myWindowManagerListener); + myListenerDisposable = Disposer.newDisposable(); + ToolWindowManagerEx toolWindowManager = (ToolWindowManagerEx)ToolWindowManager.getInstance(project); + toolWindowManager.addToolWindowManagerListener(myWindowManagerListener, myListenerDisposable); } JRootPane rootPane = myComponent.getRootPane(); if (rootPane != null) { diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 138a5e3b60b5..ca93464c5653 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -523,8 +523,8 @@ action.ClassNameCompletion.description=Complete class name and add import for it action.InsertLiveTemplate.text=Insert Live _Template... action.InsertLiveTemplate.description=Show popup list of live templates starting with the specified prefix action.ExpandLiveTemplateByTab.text=Expand Live Template by Tab -action.ExpandLiveTemplateCustom.text=Expand Live Template -action.ExpandLiveTemplateCustom.description=Invoke the live template with the prefix typed in the editor +action.ExpandLiveTemplateCustom.text=Expand Live Template / Emmet Abbreviation +action.ExpandLiveTemplateCustom.description=Invoke the live template that bound to 'Custom shortcut' with the prefix typed in the editor action.SurroundWithLiveTemplate.text=Surround with Live Tem_plate... action.SurroundWithLiveTemplate.description=Surrounds the selection with one of the template action.CommentByLineComment.text=Comment with _Line Comment diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java index c999c6dfed37..ee1575e88dc7 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java @@ -111,6 +111,16 @@ public class EditorImplTest extends AbstractEditorTest { assertEquals(new VisualPosition(0, 5), myEditor.logicalToVisualPosition(new LogicalPosition(0, 3))); } + + public void testNavigationIntoFoldedRegionWithSoftWrapsEnabled() throws Exception { + init("something"); + addCollapsedFoldRegion(4, 8, "..."); + EditorTestUtil.configureSoftWraps(myEditor, 1000); + + myEditor.getCaretModel().moveToOffset(5); + + assertEquals(new VisualPosition(0, 5), myEditor.getCaretModel().getVisualPosition()); + } private void init(String text) throws IOException { configureFromFileText(getTestName(false) + ".txt", text); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/EnforcedPlaintTextFileTypeManagerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/EnforcedPlaintTextFileTypeManagerTest.java index b7cefc60d1f6..70670acf3097 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/EnforcedPlaintTextFileTypeManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/EnforcedPlaintTextFileTypeManagerTest.java @@ -19,6 +19,7 @@ import com.intellij.openapi.file.exclude.EnforcedPlainTextFileTypeFactory; import com.intellij.openapi.file.exclude.EnforcedPlainTextFileTypeManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; +import com.intellij.util.ui.UIUtil; /** * @author Rustam Vishnyakov @@ -30,6 +31,7 @@ public class EnforcedPlaintTextFileTypeManagerTest extends LightPlatformCodeInsi FileType originalType = file.getFileType(); assertEquals("JAVA", originalType.getName()); manager.markAsPlainText(getProject(), file); + UIUtil.dispatchAllInvocationEvents(); // reparseFiles in invokeLater FileType changedType = file.getFileType(); assertEquals(EnforcedPlainTextFileTypeFactory.ENFORCED_PLAIN_TEXT, changedType.getName()); manager.resetOriginalFileType(getProject(), file); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java index df484cce9a83..2ac2dbe89422 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java @@ -278,14 +278,16 @@ public class FileTypesTest extends PlatformTestCase { } public void testReDetectOnContentsChange() throws IOException { - FileType fileType = FileTypeRegistry.getInstance().getFileTypeByFileName("x" + ModuleFileType.DOT_DEFAULT_EXTENSION); + final FileTypeRegistry fileTypeManager = FileTypeRegistry.getInstance(); + assertTrue(fileTypeManager.getClass().getName(), fileTypeManager instanceof FileTypeManagerImpl); + FileType fileType = fileTypeManager.getFileTypeByFileName("x" + ModuleFileType.DOT_DEFAULT_EXTENSION); assertTrue(fileType.toString(), fileType instanceof ModuleFileType); - fileType = FileTypeRegistry.getInstance().getFileTypeByFileName("x" + ProjectFileType.DOT_DEFAULT_EXTENSION); + fileType = fileTypeManager.getFileTypeByFileName("x" + ProjectFileType.DOT_DEFAULT_EXTENSION); assertTrue(fileType.toString(), fileType instanceof ProjectFileType); - FileType module = FileTypeRegistry.getInstance().findFileTypeByName("IDEA_MODULE"); + FileType module = fileTypeManager.findFileTypeByName("IDEA_MODULE"); assertNotNull(module); assertFalse(module.equals(PlainTextFileType.INSTANCE)); - FileType project = FileTypeRegistry.getInstance().findFileTypeByName("IDEA_PROJECT"); + FileType project = fileTypeManager.findFileTypeByName("IDEA_PROJECT"); assertNotNull(project); assertFalse(project.equals(PlainTextFileType.INSTANCE)); @@ -296,7 +298,7 @@ public class FileTypesTest extends PlatformTestCase { public FileType detect(@NotNull VirtualFile file, @NotNull ByteSequence firstBytes, @Nullable CharSequence firstCharsIfText) { detectorCalled.add(file); String text = firstCharsIfText.toString(); - FileType result = text.startsWith("TYPE:") ? FileTypeRegistry.getInstance().findFileTypeByName(StringUtil.trimStart(text, "TYPE:")) : null; + FileType result = text.startsWith("TYPE:") ? fileTypeManager.findFileTypeByName(StringUtil.trimStart(text, "TYPE:")) : null; System.out.println("T: my detector run for "+file.getName()+"; result: "+(result == null ? null : result.getName())); return result; } @@ -308,6 +310,7 @@ public class FileTypesTest extends PlatformTestCase { }; Extensions.getRootArea().getExtensionPoint(FileTypeRegistry.FileTypeDetector.EP_NAME).registerExtension(detector); try { + System.out.println("T: ------"); File d = createTempDirectory(); File f = new File(d, "xx.asfdasdfas"); FileUtil.writeToFile(f, "akjdhfksdjgf"); @@ -315,13 +318,16 @@ public class FileTypesTest extends PlatformTestCase { ensureRedetected(vFile, detectorCalled); assertTrue(vFile.getFileType().toString(), vFile.getFileType() instanceof PlainTextFileType); + System.out.println("T: ------"); VfsUtil.saveText(vFile, "TYPE:IDEA_MODULE"); ensureRedetected(vFile, detectorCalled); assertTrue(vFile.getFileType().toString(), vFile.getFileType() instanceof ModuleFileType); + System.out.println("T: ------"); VfsUtil.saveText(vFile, "TYPE:IDEA_PROJECT"); ensureRedetected(vFile, detectorCalled); assertTrue(vFile.getFileType().toString(), vFile.getFileType() instanceof ProjectFileType); + System.out.println("T: ------"); } finally { Extensions.getRootArea().getExtensionPoint(FileTypeRegistry.FileTypeDetector.EP_NAME).unregisterExtension(detector); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java index f1884e98875b..5545d44c9d8a 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/progress/impl/ProgressIndicatorTest.java @@ -22,6 +22,7 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.progress.*; import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.progress.util.ProgressIndicatorUtils; +import com.intellij.openapi.progress.util.ProgressWrapper; import com.intellij.openapi.progress.util.ReadTask; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.wm.ex.ProgressIndicatorEx; @@ -373,6 +374,34 @@ public class ProgressIndicatorTest extends LightPlatformTestCase { }).assertTiming(); } + public void testWrapperIndicatorGotCanceledTooWhenInnerIndicatorHas() { + final ProgressIndicator progress = new ProgressIndicatorBase(){ + @Override + protected boolean isCancelable() { + return true; + } + }; + try { + ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() { + @Override + public void run() { + assertFalse(ProgressManagerImpl.threadsUnderCanceledIndicator.contains(Thread.currentThread())); + assertTrue(!progress.isCanceled()); + progress.cancel(); + assertTrue(ProgressManagerImpl.threadsUnderCanceledIndicator.contains(Thread.currentThread())); + assertTrue(progress.isCanceled()); + while (true) { // wait for PCE + ProgressManager.checkCanceled(); + } + } + }, ProgressWrapper.wrap(progress)); + fail("PCE must have been thrown"); + } + catch (ProcessCanceledException ignored) { + + } + } + private static class ProgressIndicatorStub implements ProgressIndicatorEx { private volatile boolean myCanceled; diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 603ae1cbcbe1..0bbeb81c4c79 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -592,6 +592,12 @@ public class StructuralSearchTest extends StructuralSearchTestCase { String pattern3 = "\"'String\""; assertEquals("String literal", 1, findMatchesCount(s, pattern3)); + + String pattern4 = "\"test\""; + String source = "@SuppressWarnings(\"test\") class A {" + + " @SuppressWarnings({\"other\", \"test\"}) String field;" + + "}"; + assertEquals("String literal in annotation", 2, findMatchesCount(source, pattern4)); } public void testCovariantArraySearch() { diff --git a/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java b/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java index 2881d4b4b238..1318032fdcb6 100644 --- a/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java +++ b/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java @@ -62,6 +62,11 @@ public class MockPsiDocumentManager extends PsiDocumentManager { return document.getImmutableCharSequence(); } + @Override + public long getLastCommittedStamp(@NotNull Document document) { + return document.getModificationStamp(); + } + @Override @NotNull public Document[] getUncommittedDocuments() { diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index c719a74d55aa..be1f06ba103c 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -487,3 +487,5 @@ enable.recursive.document.changes.description=Enables performing document change editor.caret.width=2 editor.caret.width.description=Caret width editor.caret.width.restartRequired=true + +editor.transparent.scrollbar=false diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 97352ca3ef1a..d483e1301aa2 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -515,11 +515,7 @@ public class UIUtil { char c = e.getKeyChar(); if (c < 0x20 || c == 0x7F) return false; - if (SystemInfo.isMac) { - return !e.isMetaDown() && !e.isControlDown(); - } - - return !e.isAltDown() && !e.isControlDown(); + return !e.isMetaDown() && !e.isAltDown() && !e.isControlDown(); } public static int getStringY(@NotNull final String string, @NotNull final Rectangle bounds, @NotNull final Graphics2D g) { diff --git a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java index d693b722b56b..e42a7a50a532 100644 --- a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java +++ b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java @@ -116,7 +116,12 @@ class XmlSerializerImpl { if (binding == null) { binding = _getNonCachedClassBinding(aClass, accessor, originalType); map.put(key, binding); - binding.init(); + try { + binding.init(); + } catch (XmlSerializationException e) { + map.remove(key); + throw e; + } } return binding; } diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/GraphCommitImpl.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/GraphCommitImpl.java index 99a0337d969f..a8b3dcfc0027 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/GraphCommitImpl.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/GraphCommitImpl.java @@ -15,20 +15,29 @@ */ package com.intellij.vcs.log.graph; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ImmutableList; import org.jetbrains.annotations.NotNull; import java.util.List; -public class GraphCommitImpl implements GraphCommit { +public class GraphCommitImpl extends ImmutableList implements GraphCommit{ @NotNull private final CommitId myId; - @NotNull private final List myParents; + @NotNull private final Object myParents; private final long myTimestamp; public GraphCommitImpl(@NotNull CommitId id, @NotNull List parents, long timestamp) { myId = id; - myParents = parents; myTimestamp = timestamp; + if (parents.isEmpty()) { + myParents = ArrayUtil.EMPTY_OBJECT_ARRAY; + } else if (parents.size() == 1) { + myParents = parents.get(0); + assert !(myParents instanceof Object[]); + } else { + myParents = parents.toArray(); + } } @NotNull @@ -40,7 +49,28 @@ public class GraphCommitImpl implements GraphCommit { @NotNull @Override public List getParents() { - return myParents; + return this; + } + + @SuppressWarnings("unchecked") + @Override + public CommitId get(int index) { + if (myParents instanceof Object[]) { + Object[] array = (Object[])myParents; + if (index < 0 || index >= array.length) { + throw new ArrayIndexOutOfBoundsException(index); + } + return (CommitId)array[index]; + } + if (index != 0) { + throw new ArrayIndexOutOfBoundsException(index); + } + return (CommitId)myParents; + } + + @Override + public int size() { + return myParents instanceof Object[] ? ((Object[])myParents).length : 1; } @Override diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java index 8b94e2c4858a..a1d9e1ef39aa 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java @@ -40,6 +40,7 @@ import com.intellij.xdebugger.frame.XStackFrame; import com.intellij.xdebugger.impl.XDebugSessionImpl; import com.intellij.xdebugger.impl.actions.XDebuggerActions; import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl; +import com.intellij.xdebugger.impl.frame.actions.XDuplicateWatchAction; import com.intellij.xdebugger.impl.ui.XDebugSessionData; import com.intellij.xdebugger.impl.ui.XDebugSessionTab; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; @@ -88,6 +89,8 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa CustomShortcutSet f2Shortcut = new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0)); actionManager.getAction(XDebuggerActions.XEDIT_WATCH).registerCustomShortcutSet(f2Shortcut, tree); + new XDuplicateWatchAction().registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_DUPLICATE).getShortcutSet(), tree); + DnDManager.getInstance().registerTarget(this, tree); myRootNode = new WatchesRootNode(tree, this, session.getSessionData().getWatchExpressions()); tree.setRoot(myRootNode, false); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XDuplicateWatchAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XDuplicateWatchAction.java new file mode 100644 index 000000000000..d29545d3deaf --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XDuplicateWatchAction.java @@ -0,0 +1,45 @@ +/* + * 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.xdebugger.impl.frame.actions; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.xdebugger.impl.frame.XWatchesView; +import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; +import com.intellij.xdebugger.impl.ui.tree.nodes.WatchNode; +import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author 1 + */ +public class XDuplicateWatchAction extends XWatchesTreeActionBase { + + protected boolean isEnabled(@NotNull final AnActionEvent e, @NotNull XDebuggerTree tree) { + return !getSelectedNodes(tree, WatchNode.class).isEmpty(); + } + + @Override + protected void perform(@NotNull AnActionEvent e, @NotNull XDebuggerTree tree, @NotNull XWatchesView watchesView) { + XDebuggerTreeNode root = tree.getRoot(); + List nodes = getSelectedNodes(tree, WatchNode.class); + for (WatchNode node : nodes) { + int index = root.getIndex(node); + watchesView.addWatchExpression(node.getExpression(), index + 1, true); + } + } +} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XWatchesTreeActionBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XWatchesTreeActionBase.java index e35ab54f1fe5..297d66a4f55a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XWatchesTreeActionBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/actions/XWatchesTreeActionBase.java @@ -30,6 +30,7 @@ import java.util.List; * @author nik */ public abstract class XWatchesTreeActionBase extends AnAction { + @NotNull protected static List getSelectedNodes(final @NotNull XDebuggerTree tree, Class nodeClass) { List list = new ArrayList(); TreePath[] selectionPaths = tree.getSelectionPaths(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java index 13121c7fda16..d27c65084296 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java @@ -20,6 +20,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.AppUIUtil; import com.intellij.util.SmartList; import com.intellij.xdebugger.frame.XFullValueEvaluator; import com.intellij.xdebugger.impl.ui.XValueTextProvider; @@ -116,9 +117,14 @@ public abstract class XFetchValueActionBase extends AnAction { return index; } - public void evaluationComplete(int index, @NotNull String value, Project project) { - values.set(index, value); - finish(project); + public void evaluationComplete(final int index, @NotNull final String value, final Project project) { + AppUIUtil.invokeOnEdt(new Runnable() { + @Override + public void run() { + values.set(index, value); + finish(project); + } + }); } } diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightManager.java b/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightManager.java index 0305c3764de3..e3828664403f 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightManager.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightManager.java @@ -100,13 +100,13 @@ public class CopyrightManager extends AbstractProjectComponent implements Persis if (module == null) return; if (!newFileTracker.poll(virtualFile)) return; if (!fileTypeUtil.isSupportedFile(virtualFile)) return; - final PsiFile file = psiManager.findFile(virtualFile); - if (file == null) return; + if (psiManager.findFile(virtualFile) == null) return; application.invokeLater(new Runnable() { @Override public void run() { - if (myProject.isDisposed()) return; - if (file.isValid() && file.isWritable()) { + if (!virtualFile.isValid()) return; + final PsiFile file = psiManager.findFile(virtualFile); + if (file != null && file.isWritable()) { final CopyrightProfile opts = getCopyrightOptions(file); if (opts != null) { new UpdateCopyrightProcessor(myProject, module, file).run(); diff --git a/plugins/coverage-common/coverage-common.iml b/plugins/coverage-common/coverage-common.iml index 389fc6b1bd7e..3217ead3d827 100644 --- a/plugins/coverage-common/coverage-common.iml +++ b/plugins/coverage-common/coverage-common.iml @@ -30,6 +30,6 @@ + - - + \ No newline at end of file diff --git a/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java b/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java index c327d760e10d..8b79d0047e4d 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java +++ b/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java @@ -34,6 +34,13 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.LineTokenizer; +import com.intellij.openapi.vcs.AbstractVcs; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.actions.VcsContextFactory; +import com.intellij.openapi.vcs.history.VcsFileRevision; +import com.intellij.openapi.vcs.history.VcsHistoryProvider; +import com.intellij.openapi.vcs.history.VcsHistorySession; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.reference.SoftReference; @@ -46,11 +53,13 @@ import com.intellij.util.Alarm; import com.intellij.util.Function; import com.intellij.util.diff.Diff; import com.intellij.util.diff.FilesTooBigForDiffException; +import com.intellij.vcsUtil.VcsUtil; import gnu.trove.TIntIntHashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.io.IOException; import java.util.*; /** @@ -194,11 +203,16 @@ public class SrcFileAnnotator implements Disposable { synchronized (LOCK) { if (myOldContent == null) { if (ApplicationManager.getApplication().isDispatchThread()) return null; - final byte[] byteContent = LocalHistory.getInstance().getByteContent(f, new FileRevisionTimestampComparator() { + final LocalHistory localHistory = LocalHistory.getInstance(); + byte[] byteContent = localHistory.getByteContent(f, new FileRevisionTimestampComparator() { public boolean isSuitable(long revisionTimestamp) { return revisionTimestamp < date; } }); + + if (byteContent == null && f.getTimeStamp() > date) { + byteContent = loadFromVersionControl(date, f); + } myOldContent = new SoftReference(byteContent); } oldContent = myOldContent.get(); @@ -211,7 +225,7 @@ public class SrcFileAnnotator implements Disposable { String[] oldLines = oldToNew ? coveredLines : currentLines; String[] newLines = oldToNew ? currentLines : coveredLines; - Diff.Change change = null; + Diff.Change change; try { change = Diff.buildChanges(oldLines, newLines); } @@ -222,6 +236,41 @@ public class SrcFileAnnotator implements Disposable { return new SoftReference(getCoverageVersionToCurrentLineMapping(change, oldLines.length)); } + @Nullable + private byte[] loadFromVersionControl(long date, VirtualFile f) { + try { + final AbstractVcs vcs = VcsUtil.getVcsFor(myProject, f); + if (vcs == null) return null; + + final VcsHistoryProvider historyProvider = vcs.getVcsHistoryProvider(); + if (historyProvider == null) return null; + + final FilePath filePath = VcsContextFactory.SERVICE.getInstance().createFilePathOn(f); + final VcsHistorySession session = historyProvider.createSessionFor(filePath); + if (session == null) return null; + + final List list = session.getRevisionList(); + + if (list != null) { + for (VcsFileRevision revision : list) { + final Date revisionDate = revision.getRevisionDate(); + if (revisionDate == null) { + return null; + } + + if (revisionDate.getTime() < date) { + return revision.loadContent(); + } + } + } + } + catch (Exception e) { + LOG.info(e); + return null; + } + return null; + } + public void showCoverageInformation(final CoverageSuitesBundle suite) { if (myEditor == null || myFile == null) return; final MarkupModel markupModel = DocumentMarkupModel.forDocument(myDocument, myProject, true); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java index d8a41b52bd86..991425131df9 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java @@ -16,18 +16,17 @@ package org.jetbrains.plugins.groovy.dsl; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ex.ApplicationUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.impl.LoadTextUtil; +import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.ModificationTracker; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.Trinity; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -44,10 +43,9 @@ import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.reference.SoftReference; -import com.intellij.util.ConcurrencyUtil; +import com.intellij.util.ExceptionUtil; import com.intellij.util.Function; import com.intellij.util.PathUtil; -import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.ConcurrentMultiMap; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; @@ -68,10 +66,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import java.io.File; import java.io.IOException; import java.util.*; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.*; import java.util.regex.Pattern; /** @@ -89,10 +84,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { private static final MultiMap>> filesInProcessing = new ConcurrentMultiMap>>(); - private static final ThreadPoolExecutor ourPool = new ThreadPoolExecutor(0, 1, 10, TimeUnit.SECONDS, new LinkedBlockingQueue(), ConcurrencyUtil.newNamedThreadFactory("Groovy DSL File Index Executor")); - private final EnumeratorStringDescriptor myKeyDescriptor = new EnumeratorStringDescriptor(); - private static final byte[] ENABLED_FLAG = new byte[]{(byte)239}; public GroovyDslFileIndex() { VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() { @@ -296,6 +288,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { return SoftReference.dereference(ourStandardScripts); } + @Nullable private static List> getStandardScripts() { List> result = derefStandardScripts(); if (result != null) { @@ -303,28 +296,17 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { } final GroovyFrameworkConfigNotification[] extensions = GroovyFrameworkConfigNotification.EP_NAME.getExtensions(); - - final Semaphore semaphore = new Semaphore(); - semaphore.down(); - final AtomicReference>> ref = new AtomicReference>>(); - - if (ApplicationManager.getApplication().isWriteAccessAllowed()) { - // If this method is called with write lock acquired, then the background computation shouldn't acquire read lock. - // Otherwise, we'll get a deadlock: this method will wait for the result of the background computation holding the write lock - // and the background computation won't finish because of waiting for the read lock. - // Dirty workaround: currently the background computation acquires read lock to only initialize GroovyDslExecutor, - // so, preventive GroovyDslExecutor initialization should help - GroovyDslExecutor.getIdeaVersion(); - } - ourPool.execute(new Runnable() { - @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") + Callable>> action = new Callable>>() { @Override - public void run() { + public List> call() throws Exception { + if (GdslUtil.ourGdslStopped) { + return null; + } + try { List> pairs = derefStandardScripts(); if (pairs != null) { - ref.set(pairs); - return; + return pairs; } Set classes = new HashSet(ContainerUtil.map2Set(extensions, new Function() { @@ -365,32 +347,31 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { } } } + //noinspection AssignmentToStaticFieldFromInstanceMethod ourStandardScripts = new SoftReference>>(executors); - ref.set(executors); + return executors; } catch (Throwable e) { - ref.set(new ArrayList>()); //noinspection InstanceofCatchParameter if (e instanceof Error) { GdslUtil.stopGdsl(); } LOG.error(e); - } - finally { - semaphore.up(); + return null; } } - }); + }; - while (true) { - ProgressManager.checkCanceled(); - - if (GdslUtil.ourGdslStopped) { - return Collections.emptyList(); - } - if (ref.get() != null || semaphore.waitFor(20)) { - return ref.get(); + try { + if (ApplicationManager.getApplication().isDispatchThread()) { + return action.call(); } + return ApplicationUtil.runWithCheckCanceled(action, new EmptyProgressIndicator()); + } + catch (Exception e) { + ExceptionUtil.rethrowUnchecked(e); + LOG.error(e); + return null; } } @@ -409,9 +390,10 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { List result = new ArrayList(); List> standardScripts = getStandardScripts(); - assert standardScripts != null; - for (Pair pair : standardScripts) { - result.add(new GroovyDslScript(project, null, pair.second, pair.first.getPath())); + if (standardScripts != null) { + for (Pair pair : standardScripts) { + result.add(new GroovyDslScript(project, null, pair.second, pair.first.getPath())); + } } final LinkedBlockingQueue> queue = @@ -521,8 +503,7 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { final boolean isNewRequest = !filesInProcessing.containsKey(fileUrl); filesInProcessing.putValue(fileUrl, queue); if (isNewRequest) { - ourPool.execute(parseScript); //todo bring back multi-threading when Groovy team fixes http://jira.codehaus.org/browse/GROOVY-4292 - //ApplicationManager.getApplication().executeOnPooledThread(parseScript); + ApplicationManager.getApplication().executeOnPooledThread(parseScript); } } } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/packaging/JavaFxArtifactPropertiesEditor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/packaging/JavaFxArtifactPropertiesEditor.java index e4a7b47b673c..da7ac9794849 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/packaging/JavaFxArtifactPropertiesEditor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/packaging/JavaFxArtifactPropertiesEditor.java @@ -317,7 +317,7 @@ public class JavaFxArtifactPropertiesEditor extends ArtifactPropertiesEditor { @Override protected boolean isEmpty(JavaFxManifestAttribute element) { - return element.getName().isEmpty() && element.getValue().isEmpty(); + return StringUtil.isEmpty(element.getName()) && StringUtil.isEmpty(element.getValue()); } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnApplicationSettings.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnApplicationSettings.java index 72a1539efcf4..fb3bf081d8d5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnApplicationSettings.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnApplicationSettings.java @@ -18,6 +18,7 @@ package org.jetbrains.idea.svn; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; @@ -35,7 +36,7 @@ import java.util.List; )} ) public class SvnApplicationSettings implements PersistentStateComponent { - private SvnFileSystemListenerWrapper myVFSHandler; + private SvnFileSystemListener myVFSHandler; private int mySvnProjectCount; private LimitedStringsList myLimitedStringsList; @@ -90,8 +91,7 @@ public class SvnApplicationSettings implements PersistentStateComponent> myUndoStorageContents = new ArrayList>(); private boolean myUndoingMove = false; + private boolean myIsInCommand; + @Nullable private Project myGuessedProject; + public SvnFileSystemListener() { myLfs = LocalFileSystem.getInstance(); + + myLfs.registerAuxiliaryFileOperationsHandler(this); + CommandProcessor.getInstance().addCommandListener(this); + } + + @Override + public void dispose() { + myLfs.unregisterAuxiliaryFileOperationsHandler(this); + CommandProcessor.getInstance().removeCommandListener(this); } private void addToMoveExceptions(@NotNull final Project project, @NotNull final Exception e) { @@ -113,12 +128,10 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp exceptionList.add(handleMoveException(e)); } - private VcsException handleMoveException(@NotNull Exception e) { + private static VcsException handleMoveException(@NotNull Exception e) { VcsException vcsException; - if (e instanceof SVNException && SVNErrorCode.ENTRY_EXISTS.equals(((SVNException)e).getErrorMessage().getErrorCode())) { - vcsException = createMoveTargetExistsError(e); - } - else if (e instanceof SvnBindException && ((SvnBindException)e).contains(SVNErrorCode.ENTRY_EXISTS)) { + if (e instanceof SVNException && SVNErrorCode.ENTRY_EXISTS.equals(((SVNException)e).getErrorMessage().getErrorCode()) || + e instanceof SvnBindException && ((SvnBindException)e).contains(SVNErrorCode.ENTRY_EXISTS)) { vcsException = createMoveTargetExistsError(e); } else if (e instanceof VcsException) { @@ -137,6 +150,8 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp @Nullable public File copy(final VirtualFile file, final VirtualFile toDir, final String copyName) throws IOException { + startOperation(file); + SvnVcs vcs = getVCS(toDir); if (vcs == null) { vcs = getVCS(file); @@ -220,13 +235,13 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } public boolean move(VirtualFile file, VirtualFile toDir) throws IOException { + startOperation(file); + File srcFile = getIOFile(file); File dstFile = new File(getIOFile(toDir), file.getName()); final SvnVcs vcs = getVCS(toDir); final SvnVcs sourceVcs = getVCS(file); - if (vcs == null && sourceVcs == null) return false; - if (vcs == null) { return false; } @@ -237,19 +252,19 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } if (isPendingAdd(vcs.getProject(), toDir)) { - myMovedFiles.add(new MovedFileInfo(sourceVcs.getProject(), srcFile, dstFile)); return true; } else { - final VirtualFile oldParent = file.getParent(); - myFilesToRefresh.add(oldParent); + myFilesToRefresh.add(file.getParent()); myFilesToRefresh.add(toDir); return doMove(sourceVcs, srcFile, dstFile); } } public boolean rename(VirtualFile file, String newName) throws IOException { + startOperation(file); + File srcFile = getIOFile(file); File dstFile = new File(srcFile.getParentFile(), newName); SvnVcs vcs = getVCS(file); @@ -272,19 +287,10 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp final boolean is17OrLater = format.isOrGreater(WorkingCopyFormat.ONE_DOT_SEVEN); if (is17OrLater) { Status srcStatus = getFileStatus(vcs, src); - final File toDir = dst.getParentFile(); - Status dstStatus = getFileStatus(vcs, toDir); - final boolean srcUnversioned = srcStatus == null || srcStatus.is(StatusType.STATUS_UNVERSIONED); - if (srcUnversioned && (dstStatus == null || dstStatus.is(StatusType.STATUS_UNVERSIONED))) { + if (isUnversioned(srcStatus) && (isUnversioned(vcs, dst.getParentFile()) || isUnversioned(vcs, dst)) || + for17move(vcs, src, dst, isUndo, srcStatus)) { return false; } - if (srcUnversioned) { - Status dstWasStatus = getFileStatus(vcs, dst); - if (dstWasStatus == null || dstWasStatus.is(StatusType.STATUS_UNVERSIONED)) { - return false; - } - } - if (for17move(vcs, src, dst, isUndo, srcStatus)) return false; } else { if (for16move(vcs, src, dst, isUndo)) return false; } @@ -301,9 +307,12 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp return true; } - private final static Set ourStatusesForUndoMove = new HashSet(); - static { - ourStatusesForUndoMove.add(StatusType.STATUS_ADDED); + private static boolean isUnversioned(@Nullable Status status) { + return status == null || status.is(StatusType.STATUS_UNVERSIONED); + } + + private static boolean isUnversioned(@NotNull SvnVcs vcs, @NotNull File file) { + return isUnversioned(getFileStatus(vcs, file)); } private boolean for17move(final SvnVcs vcs, final File src, final File dst, boolean undo, Status srcStatus) throws VcsException { @@ -314,7 +323,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp myUndoingMove = true; createRevertAction(vcs, dst, true).execute(); copyUnversionedMembersOfDirectory(src, dst); - if (srcStatus == null || srcStatus.is(StatusType.STATUS_UNVERSIONED)) { + if (isUnversioned(srcStatus)) { FileUtil.delete(src); } else { createRevertAction(vcs, src, true).execute(); @@ -323,8 +332,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } else { if (doUsualMove(vcs, src)) return true; // check destination directory - final Status dstParentStatus = getFileStatus(vcs, dst.getParentFile()); - if (dstParentStatus == null || dstParentStatus.is(StatusType.STATUS_UNVERSIONED)) { + if (isUnversioned(vcs, dst.getParentFile())) { try { copyFileOrDir(src, dst); } @@ -348,7 +356,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp }.execute(); } - private void copyUnversionedMembersOfDirectory(final File src, final File dst) throws SvnBindException { + private static void copyUnversionedMembersOfDirectory(final File src, final File dst) throws SvnBindException { if (src.isDirectory()) { final SvnBindException[] exc = new SvnBindException[1]; FileUtil.processFilesRecursively(src, new Processor() { @@ -374,7 +382,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } } - private void copyFileOrDir(File src, File dst) throws IOException { + private static void copyFileOrDir(File src, File dst) throws IOException { if (src.isDirectory()) { FileUtil.copyDir(src, dst); } else { @@ -382,45 +390,38 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } } - private boolean doUsualMove(SvnVcs vcs, File src) { + private static boolean doUsualMove(SvnVcs vcs, File src) { // if src is not under version control, do usual move. Status srcStatus = getFileStatus(vcs, src); return srcStatus == null || srcStatus.is(StatusType.STATUS_UNVERSIONED, StatusType.STATUS_OBSTRUCTED, StatusType.STATUS_MISSING, StatusType.STATUS_EXTERNAL); } - private boolean for16move(SvnVcs vcs, final File src, final File dst, boolean undo) throws VcsException { + private boolean for16move(SvnVcs vcs, final File src, final File dst, final boolean undo) throws VcsException { final SVNMoveClient mover = vcs.getSvnKitManager().createMoveClient(); if (undo) { myUndoingMove = true; restoreFromUndoStorage(dst); - new RepeatSvnActionThroughBusy() { - @Override - protected void executeImpl() throws VcsException { - try { + } + else if (doUsualMove(vcs, src)) return true; + + new RepeatSvnActionThroughBusy() { + @Override + protected void executeImpl() throws VcsException { + try { + if (undo) { mover.undoMove(src, dst); } - catch (SVNException e) { - throw new SvnBindException(e); - } - } - }.execute(); - } - else { - // if src is not under version control, do usual move. - if (doUsualMove(vcs, src)) return true; - new RepeatSvnActionThroughBusy() { - @Override - protected void executeImpl() throws VcsException { - try { + else { mover.doMove(src, dst); } - catch (SVNException e) { - throw new SvnBindException(e); - } } - }.execute(); - } + catch (SVNException e) { + throw new SvnBindException(e); + } + } + }.execute(); + return false; } @@ -451,10 +452,14 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp public boolean createFile(VirtualFile dir, String name) throws IOException { + startOperation(dir); + return createItem(dir, name, false, false); } public boolean createDirectory(VirtualFile dir, String name) throws IOException { + startOperation(dir); + return createItem(dir, name, true, false); } @@ -473,6 +478,8 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp * deleted: do nothing, return true (strange) */ public boolean delete(VirtualFile file) throws IOException { + startOperation(file); + final SvnVcs vcs = getVCS(file); if (vcs != null && SvnUtil.isAdminDirectory(file)) { return true; @@ -482,10 +489,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp if (VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY.equals(value)) return false; final File ioFile = getIOFile(file); - if (! SvnUtil.isSvnVersioned(vcs.getProject(), ioFile.getParentFile())) { - return false; - } - if (SvnUtil.isWorkingCopyRoot(ioFile)) { + if (!SvnUtil.isSvnVersioned(vcs, ioFile.getParentFile()) || SvnUtil.isWorkingCopyRoot(ioFile)) { return false; } @@ -503,7 +507,6 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp return true; } else { - if (vcs != null) { if (isAboveSourceOfCopyOrMove(vcs.getProject(), ioFile)) { myDeletedFiles.putValue(vcs.getProject(), ioFile); return true; @@ -521,13 +524,14 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp // packages deleted from disk should not be deleted from svn (IDEADEV-16066) if (file.isDirectory() || isUndo(vcs)) return true; } - } return false; } } @NotNull - private RepeatSvnActionThroughBusy createRevertAction(@NotNull final SvnVcs vcs, @NotNull final File file, final boolean recursive) { + private static RepeatSvnActionThroughBusy createRevertAction(@NotNull final SvnVcs vcs, + @NotNull final File file, + final boolean recursive) { return new RepeatSvnActionThroughBusy() { @Override protected void executeImpl() throws VcsException { @@ -537,7 +541,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } @NotNull - private RepeatSvnActionThroughBusy createDeleteAction(@NotNull final SvnVcs vcs, @NotNull final File file, final boolean force) { + private static RepeatSvnActionThroughBusy createDeleteAction(@NotNull final SvnVcs vcs, @NotNull final File file, final boolean force) { return new RepeatSvnActionThroughBusy() { @Override protected void executeImpl() throws VcsException { @@ -597,7 +601,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } File ioDir = getIOFile(dir); boolean pendingAdd = isPendingAdd(vcs.getProject(), dir); - if (! SvnUtil.isSvnVersioned(vcs.getProject(), ioDir) && ! pendingAdd) { + if (!SvnUtil.isSvnVersioned(vcs, ioDir) && !pendingAdd) { return false; } final File targetFile = new File(ioDir, name); @@ -643,25 +647,29 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp return false; } - public void commandStarted(CommandEvent event) { + @Override + public void commandStarted(@NotNull CommandEvent event) { + myIsInCommand = true; myUndoingMove = false; final Project project = event.getProject(); if (project == null) return; commandStarted(project); } - void commandStarted(final Project project) { + void commandStarted(@NotNull Project project) { myUndoingMove = false; myMoveExceptions.remove(project); } - public void commandFinished(CommandEvent event) { + @Override + public void commandFinished(@NotNull CommandEvent event) { + myIsInCommand = false; final Project project = event.getProject(); if (project == null) return; commandFinished(project); } - void commandFinished(final Project project) { + void commandFinished(@NotNull Project project) { checkOverwrites(project); if (myAddedFiles.containsKey(project)) { processAddedFiles(project); @@ -772,7 +780,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } } - private void runInBackground(final Project project, final String name, final Runnable runnable) { + private static void runInBackground(final Project project, final String name, final Runnable runnable) { if (ApplicationManager.getApplication().isDispatchThread()) { ProgressManager.getInstance().runProcessWithProgressSynchronously(runnable, name, false, project); } else { @@ -780,7 +788,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } } - private Runnable createAdditionRunnable(final Project project, + private static Runnable createAdditionRunnable(final Project project, final SvnVcs vcs, final Map copyFromMap, final Collection filesToProcess, @@ -828,7 +836,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp }; } - private Collection promptAboutAddition(SvnVcs vcs, + private static Collection promptAboutAddition(SvnVcs vcs, List addedVFiles, VcsShowConfirmationOption.Value value, AbstractVcsHelper vcsHelper) { @@ -900,7 +908,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp filesToProcess.addAll(confirmed); } } - if (filesToProcess != null && ! filesToProcess.isEmpty()) { + if (!filesToProcess.isEmpty()) { runInBackground(project, "Deleting files from Subversion", createDeleteRunnable(project, vcs, filesToProcess, exceptions)); } final List deletedFilesFiles = ObjectsConvertor.convert(deletedFiles, new Convertor, FilePath>() { @@ -915,9 +923,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp myFilesToRefresh.add(parent.getVirtualFile()); } } - if (filesToProcess != null) { - deletedFilesFiles.removeAll(filesToProcess); - } + deletedFilesFiles.removeAll(filesToProcess); for (FilePath file : deletedFilesFiles) { FileUtil.delete(file.getIOFile()); } @@ -930,7 +936,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } } - private Runnable createDeleteRunnable(final Project project, + private static Runnable createDeleteRunnable(final Project project, final SvnVcs vcs, final Collection filesToProcess, final List exceptions) { @@ -957,7 +963,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp }; } - private Collection promptAboutDeletion(List> deletedFiles, + private static Collection promptAboutDeletion(List> deletedFiles, SvnVcs vcs, VcsShowConfirmationOption.Value value, AbstractVcsHelper vcsHelper) { @@ -1001,9 +1007,9 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp myT = vcs.getFactory(file).createStatusClient().doStatus(file, false); } }.compute(); - boolean isAdded = StatusType.STATUS_ADDED.equals(status.getNodeStatus()); - final FilePath filePath = VcsContextFactory.SERVICE.getInstance().createFilePathOn(file); - if (isAdded) { + + final FilePath filePath = VcsUtil.getFilePath(file); + if (StatusType.STATUS_ADDED.equals(status.getNodeStatus())) { deleteAnyway.add(filePath); } else { deletedFiles.add(Pair.create(filePath, vcs.getWorkingCopyFormat(file))); @@ -1060,11 +1066,6 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp } } - private static boolean isUndoOrRedo(@NotNull final Project project) { - final UndoManager undoManager = UndoManager.getInstance(project); - return undoManager.isUndoInProgress() || undoManager.isRedoInProgress(); - } - private static boolean isUndo(SvnVcs vcs) { if (vcs == null || vcs.getProject() == null) { return false; @@ -1073,6 +1074,20 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp return UndoManager.getInstance(p).isUndoInProgress(); } + public void startOperation(@NotNull VirtualFile file) { + if (!myIsInCommand) { + // currently actions like "new project", "import project" (probably also others) are not performed under command + myGuessedProject = ProjectLocator.getInstance().guessProjectForFile(file); + if (myGuessedProject != null) { + commandStarted(myGuessedProject); + } + } + } + public void afterDone(final ThrowableConsumer invoker) { + if (!myIsInCommand && myGuessedProject != null) { + commandFinished(myGuessedProject); + myGuessedProject = null; + } } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListenerWrapper.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListenerWrapper.java deleted file mode 100644 index 8f23eeb8d0a8..000000000000 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileSystemListenerWrapper.java +++ /dev/null @@ -1,187 +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 org.jetbrains.idea.svn; - -import com.intellij.openapi.Disposable; -import com.intellij.openapi.command.CommandEvent; -import com.intellij.openapi.command.CommandListener; -import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectLocator; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.vfs.LocalFileOperationsHandler; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ThrowableConsumer; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -public class SvnFileSystemListenerWrapper { - private final LocalFileOperationsHandler myProxy; - private final CommandListener myListener; - - public SvnFileSystemListenerWrapper(final SvnFileSystemListener delegate) { - final MyCommandListener listener = new MyCommandListener(delegate); - myListener = listener; - final MyStorage storage = new MyStorage(listener); - myProxy = (LocalFileOperationsHandler) Proxy.newProxyInstance(LocalFileOperationsHandler.class.getClassLoader(), - new Class[]{LocalFileOperationsHandler.class}, new MyInvoker(storage, delegate)); - } - - public void registerSelf() { - LocalFileSystem.getInstance().registerAuxiliaryFileOperationsHandler(myProxy); - CommandProcessor.getInstance().addCommandListener(myListener); - } - - public void unregisterSelf() { - LocalFileSystem.getInstance().unregisterAuxiliaryFileOperationsHandler(myProxy); - CommandProcessor.getInstance().removeCommandListener(myListener); - } - - private static class MyCommandListener implements CommandListener, MyMarker { - private volatile boolean myInCommand; - private final SvnFileSystemListener myDelegate; - - public MyCommandListener(final SvnFileSystemListener delegate) { - myDelegate = delegate; - } - - public void start(final Project project) { - if (!myInCommand && project != null) { - myDelegate.commandStarted(project); - } - } - - public void finish(final Project project) { - if (! myInCommand && project != null) { - myDelegate.commandFinished(project); - } - } - - public void commandStarted(CommandEvent event) { - myInCommand = true; - myDelegate.commandStarted(event); - } - - public void beforeCommandFinished(CommandEvent event) { - myDelegate.beforeCommandFinished(event); - } - - public void commandFinished(CommandEvent event) { - myInCommand = false; - myDelegate.commandFinished(event); - } - - public void undoTransparentActionStarted() { - myDelegate.undoTransparentActionStarted(); - } - - public void undoTransparentActionFinished() { - myDelegate.undoTransparentActionFinished(); - } - } - - private interface MyMarker { - void start(final Project project); - void finish(final Project project); - } - - private static class MyStorage implements InvocationHandler { - private final MyMarker myMarker; - private final Map> myStarted; - - private MyStorage(final MyMarker marker) { - myMarker = marker; - myStarted = new HashMap>(); - } - - @Nullable - private static Project getProject(Object[] args) { - for (Object arg : args) { - if (arg instanceof VirtualFile) { - return ProjectLocator.getInstance().guessProjectForFile((VirtualFile) arg); - } - } - return null; - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - final Project project = getProject(args); - if (project != null) { - final Pair pair = myStarted.get(project); - if (pair != null && method.getName().equals(pair.getFirst()) && Arrays.equals(args, pair.getSecond())) { - myMarker.finish(project); - } - } - //dont return null for auto unboxing to not face NPE - return "boolean".equals(method.getReturnType().getName()) ? Boolean.TRUE : null; - } - - private void register(final Method method, final Object[] args) { - final Object[] newArr = new Object[args.length]; - System.arraycopy(args, 0, newArr, 0, args.length); - final Project project = getProject(args); - if (project != null) { - myMarker.start(project); - myStarted.put(project, Pair.create(method.getName(), newArr)); - Disposer.register(project, new Disposable() { - public void dispose() { - myStarted.remove(project); - } - }); - } - } - } - - private static class MyInvoker implements InvocationHandler { - private final Object myDelegate; - private final MyStorage myParent; - private final LocalFileOperationsHandler myParentProxy; - - private MyInvoker(final MyStorage parent, Object delegate) { - myParent = parent; - myDelegate = delegate; - myParentProxy = (LocalFileOperationsHandler) Proxy.newProxyInstance(LocalFileOperationsHandler.class.getClassLoader(), - new Class[]{LocalFileOperationsHandler.class}, myParent); - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if ("afterDone".equals(method.getName()) && args.length == 1) { - ((ThrowableConsumer)args[0]).consume(myParentProxy); - return null; - } - - if (LocalFileOperationsHandler.class.equals(method.getDeclaringClass())) { - myParent.register(method, args); - } - if ("equals".equals(method.getName())) { - return args[0].equals(this); - } - else if ("hashCode".equals(method.getName())) { - return 1; - } - return method.invoke(myDelegate, args); - } - } -} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index 5fc354cb614b..a955b7094d26 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -510,15 +510,6 @@ public class SvnUtil { } } - @Nullable - public static VirtualFile correctRoot(final Project project, final VirtualFile file) { - if (file.getPath().length() == 0) { - // project root - return project.getBaseDir(); - } - return file; - } - public static boolean checkRepositoryVersion15(@NotNull SvnVcs vcs, @NotNull String url) { // Merge info tracking is supported in repositories since svn 1.5 (June 2008) - see http://subversion.apache.org/docs/release-notes/. // But still some users use 1.4 repositories and currently we need to know if repository supports merge info for some code flows. diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java index 0e0fce947088..d157fee66cbd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java @@ -24,6 +24,7 @@ import com.intellij.openapi.ui.MultiLineLabelUI; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.*; import com.intellij.ui.components.JBList; @@ -31,7 +32,10 @@ import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.RootUrlInfo; +import org.jetbrains.idea.svn.SvnBundle; +import org.jetbrains.idea.svn.SvnUtil; +import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.jetbrains.idea.svn.dialogs.SelectLocationDialog; import org.tmatesoft.svn.core.SVNURL; @@ -42,7 +46,6 @@ import javax.swing.event.DocumentEvent; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.io.File; import java.util.ArrayList; import java.util.List; @@ -78,9 +81,10 @@ public class BranchConfigurationDialog extends DialogWrapper { myTrunkLocationTextField.setText(configuration.getTrunkUrl()); myTrunkLocationTextField.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { - final String selectedUrl = SelectLocationDialog.selectLocation(project, myTrunkLocationTextField.getText()); - if (selectedUrl != null) { - myTrunkLocationTextField.setText(selectedUrl); + Pair selectionData = SelectLocationDialog.selectLocation(project, rootUrl); + + if (selectionData != null && selectionData.getFirst() != null) { + myTrunkLocationTextField.setText(selectionData.getFirst()); } } }); @@ -154,7 +158,6 @@ public class BranchConfigurationDialog extends DialogWrapper { boolean isAncestor = SVNURLUtil.isAncestor(myRootUrl, url); boolean areNotSame = isAncestor && !url.equals(myRootUrl); - myTrunkLocationTextField.getButton().setEnabled(isAncestor); if (areNotSame) { myConfiguration.setTrunkUrl(url.toDecodedString()); } @@ -188,34 +191,19 @@ public class BranchConfigurationDialog extends DialogWrapper { return "Subversion.BranchConfigurationDialog"; } - public static void configureBranches(final Project project, final VirtualFile file) { - configureBranches(project, file, false); - } - - public static void configureBranches(final Project project, final VirtualFile file, final boolean isRoot) { - final VirtualFile vcsRoot = (isRoot) ? file : getRoot(project, file); - if (vcsRoot == null) { + public static void configureBranches(final Project project, @Nullable VirtualFile file) { + if (file == null) { return; } - final VirtualFile directory = SvnUtil.correctRoot(project, file); - if (directory == null) { - return; - } - final RootUrlInfo wcRoot = SvnVcs.getInstance(project).getSvnFileUrlMapping().getWcRootForFilePath(new File(directory.getPath())); + final RootUrlInfo wcRoot = SvnVcs.getInstance(project).getSvnFileUrlMapping().getWcRootForFilePath(VfsUtilCore.virtualToIoFile(file)); if (wcRoot == null) { return; } - final SVNURL rootUrl = wcRoot.getRepositoryUrlUrl(); - if (rootUrl == null) { - Messages.showErrorDialog(project, SvnBundle.message("configure.branches.error.no.connection.title"), - SvnBundle.message("configure.branches.title")); - return; - } SvnBranchConfigurationNew configuration; try { - configuration = SvnBranchConfigurationManager.getInstance(project).get(vcsRoot); + configuration = SvnBranchConfigurationManager.getInstance(project).get(file); } catch (VcsException ex) { Messages.showErrorDialog(project, "Error loading branch configuration: " + ex.getMessage(), @@ -224,18 +212,14 @@ public class BranchConfigurationDialog extends DialogWrapper { } final SvnBranchConfigurationNew clonedConfiguration = configuration.copy(); - BranchConfigurationDialog dlg = new BranchConfigurationDialog(project, clonedConfiguration, rootUrl, vcsRoot, wcRoot.getUrl()); + BranchConfigurationDialog dlg = + new BranchConfigurationDialog(project, clonedConfiguration, wcRoot.getRepositoryUrlUrl(), file, wcRoot.getUrl()); dlg.show(); if (dlg.isOK()) { - SvnBranchConfigurationManager.getInstance(project).setConfiguration(vcsRoot, clonedConfiguration); + SvnBranchConfigurationManager.getInstance(project).setConfiguration(file, clonedConfiguration); } } - private static VirtualFile getRoot(Project project, VirtualFile file) { - RootUrlInfo path = SvnVcs.getInstance(project).getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath())); - return path == null ? null : path.getVirtualFile(); - } - private static class MyListModel extends AbstractListModel { private final SvnBranchConfigurationNew myConfiguration; private List myBranchUrls; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/ConfigureBranchesAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/ConfigureBranchesAction.java index 3615c4b4792d..0d65165d05cf 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/ConfigureBranchesAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/ConfigureBranchesAction.java @@ -61,6 +61,6 @@ public class ConfigureBranchesAction extends AnAction implements DumbAware { return; } final SvnChangeList svnList = (SvnChangeList) cls[0]; - BranchConfigurationDialog.configureBranches(project, svnList.getRoot(), true); + BranchConfigurationDialog.configureBranches(project, svnList.getRoot()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.java index 95ae986dd72d..37cc859bfbf2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.java @@ -184,7 +184,7 @@ public class CreateBranchOrTagDialog extends DialogWrapper { }); myBranchTagBaseComboBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - BranchConfigurationDialog.configureBranches(project, mySrcVirtualFile, true); + BranchConfigurationDialog.configureBranches(project, mySrcVirtualFile); updateBranchTagBases(); updateControls(); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SelectBranchPopup.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SelectBranchPopup.java index 445ce4e9afe3..90b7c663da40 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SelectBranchPopup.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SelectBranchPopup.java @@ -173,7 +173,7 @@ public class SelectBranchPopup { if (CONFIGURE_MESSAGE.equals(selectedValue)) { return doFinalStep(new Runnable() { public void run() { - BranchConfigurationDialog.configureBranches(myProject, myVcsRoot, true); + BranchConfigurationDialog.configureBranches(myProject, myVcsRoot); } }); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/CmdBrowseClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/CmdBrowseClient.java index bceb516caef3..239e7b6ab225 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/CmdBrowseClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/browse/CmdBrowseClient.java @@ -29,6 +29,7 @@ import org.jetbrains.idea.svn.commandLine.CommandExecutor; import org.jetbrains.idea.svn.commandLine.CommandUtil; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.jetbrains.idea.svn.commandLine.SvnCommandName; +import org.jetbrains.idea.svn.info.Info; import org.jetbrains.idea.svn.lock.Lock; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; @@ -62,9 +63,10 @@ public class CmdBrowseClient extends BaseSvnClient implements BrowseClient { parameters.add("--xml"); CommandExecutor command = execute(myVcs, target, SvnCommandName.list, parameters, null); + Info info = myFactory.createInfoClient().doInfo(target.getURL(), target.getPegRevision(), revision); try { - parseOutput(target.getURL(), command, handler); + parseOutput(target.getURL(), command, handler, info != null ? info.getRepositoryRootURL() : null); } catch (SVNException e) { throw new SvnBindException(e); @@ -89,15 +91,18 @@ public class CmdBrowseClient extends BaseSvnClient implements BrowseClient { return listener.getCommittedRevision(); } - private static void parseOutput(@NotNull SVNURL url, @NotNull CommandExecutor command, @Nullable DirectoryEntryConsumer handler) - throws VcsException, SVNException { + private static void parseOutput(@NotNull SVNURL url, + @NotNull CommandExecutor command, + @Nullable DirectoryEntryConsumer handler, + @Nullable SVNURL repositoryUrl) + throws VcsException, SVNException { try { TargetLists lists = CommandUtil.parse(command.getOutput(), TargetLists.class); if (handler != null && lists != null) { for (TargetList list : lists.lists) { for (Entry entry : list.entries) { - handler.consume(entry.toDirectoryEntry(url)); + handler.consume(entry.toDirectoryEntry(url, repositoryUrl)); } } } @@ -140,9 +145,8 @@ public class CmdBrowseClient extends BaseSvnClient implements BrowseClient { public Lock.Builder lock; @NotNull - public DirectoryEntry toDirectoryEntry(@NotNull SVNURL url) throws SVNException { - // TODO: repository is not used for now - return new DirectoryEntry(url.appendPath(name, false), null, PathUtil.getFileName(name), kind, + public DirectoryEntry toDirectoryEntry(@NotNull SVNURL url, @Nullable SVNURL repositoryUrl) throws SVNException { + return new DirectoryEntry(url.appendPath(name, false), repositoryUrl, PathUtil.getFileName(name), kind, commit != null ? commit.build() : null, name); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java index 1286c88ecb29..d06b67093aa6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java @@ -221,7 +221,7 @@ public class CopiesPanel { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { if (CONFIGURE_BRANCHES.equals(e.getDescription())) { if (! checkRoot(root, wcInfo.getPath(), " invoke Configure Branches")) return; - BranchConfigurationDialog.configureBranches(myProject, root, true); + BranchConfigurationDialog.configureBranches(myProject, root); } else if (FIX_DEPTH.equals(e.getDescription())) { final int result = Messages.showOkCancelDialog(myVcs.getProject(), "You are going to checkout into '" + wcInfo.getPath() + "' with 'infinity' depth.\n" + diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java index f7e54a64f0ad..d6eaf61509bf 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java @@ -18,13 +18,13 @@ package org.jetbrains.idea.svn.dialogs; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataProvider; -import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vcs.vfs.VcsFileSystem; import com.intellij.openapi.vcs.vfs.VcsVirtualFile; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.pom.NavigatableAdapter; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.SpeedSearchComparator; import com.intellij.ui.TreeSpeedSearch; @@ -282,7 +282,18 @@ public class RepositoryBrowserComponent extends JPanel implements Disposable, Da return null; } final VirtualFile vcsFile = getSelectedVcsFile(); - return vcsFile != null ? new OpenFileDescriptor(project, vcsFile) : null; + + // do not return OpenFileDescriptor instance here as in that case SelectInAction will be enabled and its invocation (using keyboard) + // will raise error - see IDEA-104113 - because of the following operations inside SelectInAction.actionPerformed(): + // - at first VcsVirtualFile content will be loaded which for svn results in showing progress dialog + // - then DataContext from SelectInAction will still be accessed which results in error as current event count has already changed + // (because of progress dialog) + return vcsFile != null ? new NavigatableAdapter() { + @Override + public void navigate(boolean requestFocus) { + navigate(project, vcsFile, requestFocus); + } + } : null; } else if (CommonDataKeys.PROJECT.is(dataId)) { return myVCS.getProject(); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java index 83d895b93ffc..6f386abf1fa6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java @@ -25,7 +25,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; -import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.progress.ProgressIndicator; @@ -192,6 +191,7 @@ public class RepositoryBrowserDialog extends DialogWrapper { } protected JPopupMenu createPopup(boolean toolWindow) { + ActionManager actionManager = ActionManager.getInstance(); DefaultActionGroup group = new DefaultActionGroup(); DefaultActionGroup newGroup = new DefaultActionGroup("_New", true); final RepositoryBrowserComponent browser = getRepositoryBrowser(); @@ -200,7 +200,7 @@ public class RepositoryBrowserDialog extends DialogWrapper { group.add(newGroup); group.addSeparator(); if (toolWindow) { - group.add(new OpenAction()); + group.add(actionManager.getAction(IdeActions.ACTION_EDIT_SOURCE)); group.add(new HistoryAction()); } group.add(new CheckoutAction()); @@ -218,7 +218,7 @@ public class RepositoryBrowserDialog extends DialogWrapper { group.add(new RefreshAction(browser)); group.add(new EditLocationAction(browser)); group.add(new DiscardLocationAction(browser)); - ActionPopupMenu menu = ActionManager.getInstance().createActionPopupMenu(PLACE_MENU, group); + ActionPopupMenu menu = actionManager.createActionPopupMenu(PLACE_MENU, group); return menu.getComponent(); } @@ -928,23 +928,6 @@ public class RepositoryBrowserDialog extends DialogWrapper { } } - protected class OpenAction extends AnAction { - public void update(AnActionEvent e) { - e.getPresentation().setEnabled(false); - if (myVCS == null) { - return; - } - e.getPresentation().setText("_Open", true); - e.getPresentation().setEnabled(getRepositoryBrowser().getSelectedVcsFile() != null); - } - public void actionPerformed(AnActionEvent e) { - VirtualFile vcsVF = getRepositoryBrowser().getSelectedVcsFile(); - if (vcsVF != null) { - FileEditorManager.getInstance(myVCS.getProject()).openFile(vcsVF, true); - } - } - } - protected class DetailsAction extends ToggleAction { private boolean myIsSelected; diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/ManageTemplateVariablesDialog.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/ManageTemplateVariablesDialog.java index ebb8bd39997b..17d966b65d3e 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/ManageTemplateVariablesDialog.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/ManageTemplateVariablesDialog.java @@ -2,6 +2,7 @@ package com.intellij.tasks.generic; import com.intellij.execution.util.ListTableWithButtons; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ui.AbstractTableCellEditor; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.ListTableModel; @@ -208,7 +209,7 @@ public class ManageTemplateVariablesDialog extends DialogWrapper { @Override protected boolean isEmpty(TemplateVariable element) { - return element.getName().isEmpty() && element.getValue().isEmpty(); + return StringUtil.isEmpty(element.getName()) && StringUtil.isEmpty(element.getValue()); } @Override diff --git a/python/gen/icons/PythonIcons.java b/python/gen/icons/PythonIcons.java index f98387fedc29..f18ef6dfab36 100644 --- a/python/gen/icons/PythonIcons.java +++ b/python/gen/icons/PythonIcons.java @@ -52,6 +52,7 @@ public class PythonIcons { public static final Icon PythonConsole = load("/icons/com/jetbrains/python/pythonConsole.png"); // 16x16 public static final Icon PythonConsoleToolWindow = load("/icons/com/jetbrains/python/pythonConsoleToolWindow.png"); // 13x13 public static final Icon PythonTests = load("/icons/com/jetbrains/python/pythonTests.png"); // 16x16 + public static final Icon RemoteInterpreter = load("/icons/com/jetbrains/python/RemoteInterpreter.png"); // 16x16 public static final Icon TemplateRoot = load("/icons/com/jetbrains/python/templateRoot.png"); // 16x16 public static final Icon Virtualenv = load("/icons/com/jetbrains/python/virtualenv.png"); // 16x16 diff --git a/python/helpers/pydev/pydev_console_utils.py b/python/helpers/pydev/pydev_console_utils.py index d12419e19e57..043351587155 100644 --- a/python/helpers/pydev/pydev_console_utils.py +++ b/python/helpers/pydev/pydev_console_utils.py @@ -387,7 +387,7 @@ class BaseInterpreterInterface: def getArray(self, attr, roffset, coffset, rows, cols, format): xml = "" - name = ".".join(attr.split("\t")) + name = attr.split("\t")[-1] array = pydevd_vars.evalInContext(name, self.getNamespace(), self.getNamespace()) if rows == -1 and cols == -1: diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py index 8b7596d5818c..8f5fea6f0fb2 100644 --- a/python/helpers/pydev/pydevd_comm.py +++ b/python/helpers/pydev/pydevd_comm.py @@ -974,15 +974,15 @@ class InternalGetArray(InternalThreadCommand): self.thread_id = thread_id self.frame_id = frame_id self.scope = scope - self.name = ".".join(attrs.split("\t")) + self.name = attrs.split("\t")[-1] self.attrs = attrs self.roffset = int(roffset) self.coffset = int(coffset) self.rows = int(rows) self.cols = int(cols) self.format = format - if hasattr(self.format, 'decode'): - self.format = self.format.decode('utf-8') + if hasattr(self.format, 'encode'): + self.format = self.format.encode('utf-8') def doIt(self, dbg): try: diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbEditorProvider.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbEditorProvider.java index 6b17ce0c1bc7..5eae76c5509f 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbEditorProvider.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbEditorProvider.java @@ -67,6 +67,6 @@ public class IpnbEditorProvider implements FileEditorProvider, DumbAware { @NotNull @Override public FileEditorPolicy getPolicy() { - return FileEditorPolicy.PLACE_BEFORE_DEFAULT_EDITOR; + return FileEditorPolicy.HIDE_DEFAULT_EDITOR; } } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbFileEditor.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbFileEditor.java index ad82df9d56b5..685ea9d27620 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbFileEditor.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbFileEditor.java @@ -6,19 +6,15 @@ import com.intellij.icons.AllIcons; import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.*; -import com.intellij.openapi.fileEditor.ex.FileEditorProviderManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.pom.Navigatable; import com.intellij.ui.JBColor; import com.intellij.ui.ScrollPaneFactory; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.ipnb.editor.actions.*; import org.jetbrains.plugins.ipnb.editor.panels.*; import org.jetbrains.plugins.ipnb.editor.panels.code.IpnbCodePanel; @@ -41,15 +37,15 @@ import java.util.List; /** * @author traff */ -public class IpnbFileEditor extends UserDataHolderBase implements FileEditor, TextEditor { +public class IpnbFileEditor extends UserDataHolderBase implements FileEditor { private final VirtualFile myFile; private final String myName; private final JComponent myEditorPanel; - private final TextEditor myEditor; private final IpnbFilePanel myIpnbFilePanel; + private final Document myDocument; private ComboBox myCellTypeCombo; private static final String codeCellType = "Code"; private static final String markdownCellType = "Markdown"; @@ -63,12 +59,14 @@ public class IpnbFileEditor extends UserDataHolderBase implements FileEditor, Te public IpnbFileEditor(Project project, final VirtualFile vFile) { + myDocument = FileDocumentManager.getInstance().getDocument(vFile); project.getMessageBus().connect(this).subscribe(FileEditorManagerListener.Before.FILE_EDITOR_MANAGER, new FileEditorManagerListener.Before.Adapter() { @Override public void beforeFileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) { if (!new File(file.getPath()).exists()) return; - final Document document = getEditor().getDocument(); - FileDocumentManager.getInstance().saveDocument(document); + + if (myDocument == null) return; + FileDocumentManager.getInstance().saveDocument(myDocument); IpnbParser.saveIpnbFile(myIpnbFilePanel); file.refresh(false, false); } @@ -78,8 +76,6 @@ public class IpnbFileEditor extends UserDataHolderBase implements FileEditor, Te myName = vFile.getName(); - myEditor = createEditor(project, vFile); - myEditorPanel = new JPanel(new BorderLayout()); myEditorPanel.setBackground(IpnbEditorUtil.getBackground()); @@ -94,6 +90,10 @@ public class IpnbFileEditor extends UserDataHolderBase implements FileEditor, Te registerHeadingActions(); } + public Document getDocument() { + return myDocument; + } + private void registerHeadingActions() { new IpnbHeading1CellAction().registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke("ctrl shift 1")), myIpnbFilePanel); new IpnbHeading2CellAction().registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke("ctrl shift 2")), myIpnbFilePanel); @@ -417,46 +417,6 @@ public class IpnbFileEditor extends UserDataHolderBase implements FileEditor, Te @Override public void dispose() { - Disposer.dispose(myEditor); - } - - @NotNull - @Override - public Editor getEditor() { - return myEditor.getEditor(); - } - - @Override - public boolean canNavigateTo(@NotNull Navigatable navigatable) { - return true; - } - - @Override - public void navigateTo(@NotNull Navigatable navigatable) { - } - - @Nullable - private static TextEditor createEditor(@NotNull Project project, @NotNull VirtualFile vFile) { - FileEditorProvider provider = getProvider(project, vFile); - - if (provider != null) { - FileEditor editor = provider.createEditor(project, vFile); - if (editor instanceof TextEditor) { - return (TextEditor)editor; - } - } - return null; - } - - @Nullable - private static FileEditorProvider getProvider(Project project, VirtualFile vFile) { - FileEditorProvider[] providers = FileEditorProviderManager.getInstance().getProviders(project, vFile); - for (FileEditorProvider provider : providers) { - if (!(provider instanceof IpnbEditorProvider)) { - return provider; - } - } - return null; } public abstract static class CellSelectionListener { diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbFilePanel.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbFilePanel.java index 5017073ebf15..0de2d5795688 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbFilePanel.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbFilePanel.java @@ -78,7 +78,7 @@ public class IpnbFilePanel extends JPanel implements Scrollable, DataProvider, D alarm.addRequest(new MySynchronizeRequest(), 10, ModalityState.stateForComponent(IpnbFilePanel.this)); } }; - myDocument = myParent.getEditor().getDocument(); + myDocument = myParent.getDocument(); myDocument.addDocumentListener(myDocumentListener); alarm.addRequest(new Runnable() { diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnection.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnection.java index f10e88856ef1..b5e1b94250ea 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnection.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnection.java @@ -23,6 +23,8 @@ public class IpnbConnection { private static final String API_URL = "/api"; private static final String KERNELS_URL = API_URL + "/kernels"; private static final String HTTP_POST = "POST"; + // TODO: Serialize cookies for the authentication message + private static final String authMessage = "{\"header\":{\"msg_id\":\"\", \"msg_type\":\"connect_request\"}, \"parent_header\":\"\", \"metadata\":{}}"; public static final String HTTP_DELETE = "DELETE"; @NotNull private final URI myURI; @@ -45,8 +47,6 @@ public class IpnbConnection { myKernelId = startKernel(); final Draft draft = new Draft17WithOrigin(); - // TODO: Serialize cookies for the authentication message - final String authMessage = "identity:foo"; myShellClient = new WebSocketClient(getShellURI(), draft) { @Override @@ -92,7 +92,7 @@ public class IpnbConnection { final PyOutContent content = gson.fromJson(msg.getContent(), PyOutContent.class); addCellOutput(content, myOutput); } - else if ("pyerr".equals(messageType)) { + else if ("pyerr".equals(messageType) || "error".equals(messageType)) { final PyErrContent content = gson.fromJson(msg.getContent(), PyErrContent.class); addCellOutput(content, myOutput); } @@ -100,7 +100,7 @@ public class IpnbConnection { final PyStreamContent content = gson.fromJson(msg.getContent(), PyStreamContent.class); addCellOutput(content, myOutput); } - else if ("pyin".equals(messageType)) { + else if ("pyin".equals(messageType) || "execute_input".equals(messageType)) { final JsonElement executionCount = msg.getContent().get("execution_count"); if (executionCount != null) { myExecCount = executionCount.getAsInt(); @@ -396,11 +396,12 @@ public class IpnbConnection { @SuppressWarnings("UnusedDeclaration") private static class PyStreamContent implements PyContent { + private String text; private String data; private String name; public String getData() { - return data; + return data == null ? text : data; } public String getName() { diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbFunctionElementType.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbFunctionElementType.java new file mode 100644 index 000000000000..80723bdb1f95 --- /dev/null +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbFunctionElementType.java @@ -0,0 +1,30 @@ +package org.jetbrains.plugins.ipnb.psi; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.stubs.IStubElementType; +import com.jetbrains.python.psi.PyFunction; +import com.jetbrains.python.psi.impl.stubs.PyFunctionElementType; +import com.jetbrains.python.psi.stubs.PyFunctionStub; +import org.jetbrains.annotations.NotNull; + +public class IpnbFunctionElementType extends PyFunctionElementType { + public IpnbFunctionElementType() { + super("IPNB_FUNCTION"); + } + + @Override + public PsiElement createElement(@NotNull ASTNode node) { + return new IpnbPyFunction(node); + } + + @Override + public PyFunction createPsi(@NotNull PyFunctionStub stub) { + return new IpnbPyFunction(stub); + } + + @Override + protected IStubElementType getStubElementType() { + return IpnbPyTokenTypes.IPNB_FUNCTION; + } +} diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyFunction.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyFunction.java new file mode 100644 index 000000000000..13589f65ec15 --- /dev/null +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyFunction.java @@ -0,0 +1,44 @@ +package org.jetbrains.plugins.ipnb.psi; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.util.ui.UIUtil; +import com.jetbrains.python.psi.impl.PyFunctionImpl; +import com.jetbrains.python.psi.stubs.PyFunctionStub; +import org.jetbrains.plugins.ipnb.editor.IpnbFileEditor; +import org.jetbrains.plugins.ipnb.editor.panels.IpnbFilePanel; +import org.jetbrains.plugins.ipnb.editor.panels.code.IpnbCodePanel; +import org.jetbrains.plugins.ipnb.editor.panels.code.IpnbCodeSourcePanel; + +public class IpnbPyFunction extends PyFunctionImpl { + + public IpnbPyFunction(ASTNode astNode) { + super(astNode); + } + + public IpnbPyFunction(PyFunctionStub stub) { + super(stub); + } + + public IpnbPyFunction(PyFunctionStub stub, IStubElementType nodeType) { + super(stub, nodeType); + } + + @Override + public void navigate(boolean requestFocus) { + final IpnbCodeSourcePanel sourcePanel = ((IpnbPyFragment)getContainingFile()).getCodeSourcePanel(); + final Editor editor = sourcePanel.getEditor(); + + final IpnbCodePanel codePanel = sourcePanel.getIpnbCodePanel(); + final IpnbFileEditor fileEditor = codePanel.getFileEditor(); + final IpnbFilePanel filePanel = fileEditor.getIpnbFilePanel(); + codePanel.setEditing(true); + filePanel.setSelectedCell(codePanel); + super.navigate(false); + UIUtil.requestFocus(editor.getContentComponent()); + + } + +} + diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyParsingContext.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyParsingContext.java index 13d1196b510d..37e78b18e843 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyParsingContext.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyParsingContext.java @@ -4,6 +4,7 @@ import com.intellij.lang.PsiBuilder; import com.intellij.psi.tree.IElementType; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.parsing.ExpressionParsing; +import com.jetbrains.python.parsing.FunctionParsing; import com.jetbrains.python.parsing.ParsingContext; import com.jetbrains.python.parsing.StatementParsing; import com.jetbrains.python.psi.LanguageLevel; @@ -12,6 +13,7 @@ import org.jetbrains.annotations.Nullable; public class IpnbPyParsingContext extends ParsingContext { private final StatementParsing myStatementParser; private final ExpressionParsing myExpressionParser; + private final FunctionParsing myFunctionParser; public IpnbPyParsingContext(final PsiBuilder builder, LanguageLevel languageLevel, @@ -19,6 +21,7 @@ public class IpnbPyParsingContext extends ParsingContext { super(builder, languageLevel, futureFlag); myStatementParser = new IpnbPyStatementParsing(this, futureFlag); myExpressionParser = new IpnbPyExpressionParsing(this); + myFunctionParser = new IpnbPyFunctionParsing(this); } @Override @@ -31,6 +34,11 @@ public class IpnbPyParsingContext extends ParsingContext { return myStatementParser; } + @Override + public FunctionParsing getFunctionParser() { + return myFunctionParser; + } + private static class IpnbPyExpressionParsing extends ExpressionParsing { public IpnbPyExpressionParsing(ParsingContext context) { super(context); @@ -68,4 +76,14 @@ public class IpnbPyParsingContext extends ParsingContext { } } + private static class IpnbPyFunctionParsing extends FunctionParsing { + + public IpnbPyFunctionParsing(ParsingContext context) { + super(context); + } + protected IElementType getFunctionType() { + return IpnbPyTokenTypes.IPNB_FUNCTION; + } + + } } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyTokenSetContributor.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyTokenSetContributor.java index d02bc3d02c1b..f06f31445b53 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyTokenSetContributor.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyTokenSetContributor.java @@ -18,4 +18,11 @@ public class IpnbPyTokenSetContributor extends PythonDialectsTokenSetContributor public TokenSet getReferenceExpressionTokens() { return IPNB_REFERENCE_EXPRESSIONS; } + + + @NotNull + @Override + public TokenSet getFunctionDeclarationTokens() { + return TokenSet.create(IpnbPyTokenTypes.IPNB_FUNCTION); + } } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyTokenTypes.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyTokenTypes.java index a271089b784d..02f69b054f8f 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyTokenTypes.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbPyTokenTypes.java @@ -1,10 +1,12 @@ package org.jetbrains.plugins.ipnb.psi; import com.jetbrains.python.psi.PyElementType; +import com.jetbrains.python.psi.impl.stubs.PyFunctionElementType; public class IpnbPyTokenTypes { public static final PyElementType IPNB_REFERENCE = new PyElementType("IPNB_REFERENCE", IpnbPyReferenceExpression.class); public static final PyElementType IPNB_TARGET = new PyElementType("IPNB_TARGET", IpnbPyTargetExpression.class); + public static final PyFunctionElementType IPNB_FUNCTION = new IpnbFunctionElementType(); private IpnbPyTokenTypes() { } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java index 26f81dddf56a..66eee2fb8a91 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java @@ -15,7 +15,7 @@ import javax.swing.*; // todo: null modifier for modify modules, class objects etc. public class PyDebugValue extends XNamedValue { private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.pydev.PyDebugValue"); - public static final int MAX_VALUE = 512; + public static final int MAX_VALUE = 256; private String myTempName = null; private final String myType; @@ -134,12 +134,23 @@ public class PyDebugValue extends XNamedValue { return "__len__".equals(name); } + private String getFullName() { + String result = myName; + PyDebugValue parent = myParent; + while (parent != null) { + result = "." + result; + result = parent.getName() + result; + parent = parent.getParent(); + } + return result; + } + @Override public void computePresentation(@NotNull XValueNode node, @NotNull XValuePlace place) { String value = PyTypeHandler.format(this); if (value.length() >= MAX_VALUE) { - node.setFullValueEvaluator(new PyFullValueEvaluator(myFrameAccessor, myName)); + node.setFullValueEvaluator(new PyFullValueEvaluator(myFrameAccessor, getFullName())); value = value.substring(0, MAX_VALUE); } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 11cc0d798e58..4459d2e7d4cc 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -109,7 +109,11 @@ public class RemoteDebugger implements ProcessDebugger { public String handshake() throws PyDebuggerException { final VersionCommand command = new VersionCommand(this, LOCAL_VERSION, SystemInfo.isUnix ? "UNIX" : "WIN"); command.execute(); - return command.getRemoteVersion(); + String version = command.getRemoteVersion(); + if (version != null) { + version = version.trim(); + } + return version; } @Override diff --git a/python/resources/icons/com/jetbrains/python/RemoteInterpreter.png b/python/resources/icons/com/jetbrains/python/RemoteInterpreter.png new file mode 100644 index 000000000000..8ce74f45ed77 Binary files /dev/null and b/python/resources/icons/com/jetbrains/python/RemoteInterpreter.png differ diff --git a/python/resources/icons/com/jetbrains/python/RemoteInterpreter@2x.png b/python/resources/icons/com/jetbrains/python/RemoteInterpreter@2x.png new file mode 100644 index 000000000000..26e7c26c2670 Binary files /dev/null and b/python/resources/icons/com/jetbrains/python/RemoteInterpreter@2x.png differ diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyCommentBreakerEnterProcessor.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyCommentBreakerEnterProcessor.java index ee8394defe9e..0a6abd4b084b 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyCommentBreakerEnterProcessor.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyCommentBreakerEnterProcessor.java @@ -19,6 +19,7 @@ import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.codeInsight.editorActions.smartEnter.SmartEnterUtil; @@ -34,12 +35,15 @@ public class PyCommentBreakerEnterProcessor implements EnterProcessor { return false; } final CaretModel caretModel = editor.getCaretModel(); - final PsiElement atCaret = psiElement.getContainingFile().findElementAt(caretModel.getOffset()); + PsiElement atCaret = psiElement.getContainingFile().findElementAt(caretModel.getOffset()); + if (atCaret instanceof PsiWhiteSpace) { + atCaret = atCaret.getPrevSibling(); + } final PsiElement comment = PsiTreeUtil.getParentOfType(atCaret, PsiComment.class, false); if (comment != null) { SmartEnterUtil.plainEnter(editor); - editor.getDocument().insertString(caretModel.getOffset(), "#"); - caretModel.moveToOffset(caretModel.getOffset() + 1); + editor.getDocument().insertString(caretModel.getOffset(), "# "); + caretModel.moveToOffset(caretModel.getOffset() + 2); return true; } return false; diff --git a/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java b/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java index 753ed4b59dec..5ad10678d068 100644 --- a/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java +++ b/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java @@ -263,7 +263,7 @@ public class AddImportHelper { continue; } final QualifiedName qName = existingImport.getImportSourceQName(); - if (qName != null && qName.toString().equals(path)) { + if (qName != null && qName.toString().equals(path) && existingImport.getRelativeLevel() == 0) { for (PyImportElement el : existingImport.getImportElements()) { if (name.equals(el.getVisibleName())) { return false; diff --git a/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java b/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java index e62910144b45..a5c9a10d0454 100644 --- a/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java +++ b/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java @@ -25,10 +25,14 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileSystemItem; import com.intellij.psi.util.QualifiedName; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * An immutable holder of information for one auto-import candidate. *

@@ -131,15 +135,15 @@ class ImportCandidateHolder implements Comparable { sb.append(((PyFunction)myImportable).getParameterList().getPresentableText(false)); } else if (myImportable instanceof PyClass) { - final PyClass[] supers = ((PyClass)myImportable).getSuperClasses(); - if (supers.length > 0) { + final List supers = ContainerUtil.mapNotNull(((PyClass)myImportable).getSuperClasses(), new Function() { + @Override + public String fun(PyClass cls) { + return PyUtil.isObjectClass(cls) ? null : cls.getName(); + } + }); + if (!supers.isEmpty()) { sb.append("("); - // ", ".join(x.getName() for x in getSuperClasses()) - final String[] superNames = new String[supers.length]; - for (int i = 0; i < supers.length; i += 1) { - superNames[i] = supers[i].getName(); - } - sb.append(StringUtil.join(superNames, ", ")); + StringUtil.join(supers, ", ", sb); sb.append(")"); } } diff --git a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java index 6d237301c293..71cef8164bcd 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java @@ -554,14 +554,7 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl throws PyDebuggerException { if (myClient != null) { try { - String fullName = var.getName(); - PyDebugValue child = var; - while (child.getParent() != null) { - child = child.getParent(); - fullName = child.getName() + "\t" + fullName; - } - - Object ret = myClient.execute(GET_ARRAY, new Object[]{fullName, rowOffset, colOffset, rows, cols, format}); + Object ret = myClient.execute(GET_ARRAY, new Object[]{var.getName(), rowOffset, colOffset, rows, cols, format}); if (ret instanceof String) { return ProtocolParser.parseArrayValues((String)ret, this); } diff --git a/python/src/com/jetbrains/python/debugger/array/AsyncArrayTableModel.java b/python/src/com/jetbrains/python/debugger/array/AsyncArrayTableModel.java index 3eb47155d316..c25ef27b6b17 100644 --- a/python/src/com/jetbrains/python/debugger/array/AsyncArrayTableModel.java +++ b/python/src/com/jetbrains/python/debugger/array/AsyncArrayTableModel.java @@ -51,7 +51,7 @@ public class AsyncArrayTableModel extends AbstractTableModel { final PyDebugValue value = myProvider.getDebugValue(); final PyDebugValue slicedValue = new PyDebugValue(myProvider.getSliceText(), value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), - value.getFrameAccessor()); + value.getParent(), value.getFrameAccessor()); ListenableFutureTask task = ListenableFutureTask.create(new Callable() { @Override diff --git a/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java b/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java index 6a2122e9b7f1..bab68147db79 100644 --- a/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java +++ b/python/src/com/jetbrains/python/debugger/array/NumpyArrayTable.java @@ -167,7 +167,7 @@ public class NumpyArrayTable { } public void init() { - init(myValue.getName(), false); + init(getDebugValue().getEvaluationExpression(), false); } public void init(final String slice, final boolean inPlace) { @@ -181,14 +181,8 @@ public class NumpyArrayTable { public void run() { final PyDebugValue value = getDebugValue(); PyDebugValue parent = value.getParent(); - String sl = slice; - - if (slice.contains(".")) { - sl = slice.substring(slice.lastIndexOf(".") + 1); - } - final PyDebugValue slicedValue = - new PyDebugValue(sl, value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), + new PyDebugValue(slice, value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), parent, value.getFrameAccessor()); final String format = getFormat().isEmpty() ? "%" : getFormat(); @@ -433,14 +427,7 @@ public class NumpyArrayTable { } public String getNodeFullName() { - String fullName = getDebugValue().getName(); - PyDebugValue child = getDebugValue(); - while (child.getParent() != null) { - child = child.getParent(); - fullName = child.getName() + "." + fullName; - } - - return fullName; + return getDebugValue().getEvaluationExpression(); } public String getFormat() { diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 37cd12906b41..b9bf5d7c63d9 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -40,8 +40,10 @@ import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.documentation.DocStringUtil; 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.QualifiedNameFinder; +import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.stubs.PropertyStubStorage; import com.jetbrains.python.psi.stubs.PyClassStub; import com.jetbrains.python.psi.stubs.PyFunctionStub; @@ -1174,11 +1176,10 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla final PyClassStub stub = getStub(); final List result = new ArrayList(); if (stub != null) { - final PsiElement parent = stub.getParentStub().getPsi(); - if (parent instanceof PyFile) { - final PyFile file = (PyFile)parent; + final PsiFile file = getContainingFile(); + if (file instanceof PyFile) { for (QualifiedName name : stub.getSuperClasses()) { - result.add(name != null ? classTypeFromQName(name, file, context) : null); + result.add(name != null ? classTypeFromQName(name, (PyFile)file, context) : null); } } } @@ -1315,47 +1316,67 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla } @Nullable - private static PsiElement getElementQNamed(@NotNull NameDefiner nameDefiner, @NotNull QualifiedName qualifiedName) { + private static PsiElement getElementQNamed(@NotNull PyFile file, @NotNull QualifiedName qualifiedName, @NotNull TypeEvalContext context) { final int componentCount = qualifiedName.getComponentCount(); final String fullName = qualifiedName.toString(); + final PyType type = new PyModuleType(file); if (componentCount == 0) { return null; } else if (componentCount == 1) { - PsiElement element = nameDefiner.getElementNamed(fullName); + PsiElement element = resolveTypeMember(type, fullName, context); if (element == null) { - element = PyBuiltinCache.getInstance(nameDefiner).getByName(fullName); + element = PyBuiltinCache.getInstance(file).getByName(fullName); } return element; } else { final String name = qualifiedName.getLastComponent(); final QualifiedName containingQName = qualifiedName.removeLastComponent(); - NameDefiner definer = nameDefiner; + PyType currentType = type; for (String component : containingQName.getComponents()) { - PsiElement element = PyUtil.turnDirIntoInit(definer.getElementNamed(component)); - if (element instanceof PyImportElement) { - element = ((PyImportElement)element).resolve(); - } - if (element instanceof NameDefiner) { - definer = (NameDefiner)element; - } - else { - definer = null; - break; + currentType = getMemberType(currentType, component, context); + if (currentType == null) { + return null; } } - if (definer != null) { - return definer.getElementNamed(name); + if (name != null) { + return resolveTypeMember(currentType, name, context); } return null; } } + @Nullable + private static PyType getMemberType(@NotNull PyType type, @NotNull String name, @NotNull TypeEvalContext context) { + final PyType result; + PsiElement element = resolveTypeMember(type, name, context); + if (element instanceof PyImportedModule) { + result = new PyImportedModuleType((PyImportedModule)element); + } + else if (element instanceof PyTypedElement) { + result = context.getType((PyTypedElement)element); + } + else { + return null; + } + if (result instanceof PyClassLikeType) { + return ((PyClassLikeType)result).toInstance(); + } + return result; + } + + @Nullable + private static PsiElement resolveTypeMember(@NotNull PyType type, @NotNull String name, @NotNull TypeEvalContext context) { + final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); + final List results = type.resolveMember(name, null, AccessDirection.READ, resolveContext); + return (results != null && !results.isEmpty()) ? results.get(0).getElement() : null; + } + @Nullable private static PyClassLikeType classTypeFromQName(@NotNull QualifiedName qualifiedName, @NotNull PyFile containingFile, @NotNull TypeEvalContext context) { - final PsiElement element = getElementQNamed(containingFile, qualifiedName); + final PsiElement element = getElementQNamed(containingFile, qualifiedName, context); if (element instanceof PyTypedElement) { final PyType type = context.getType((PyTypedElement)element); if (type instanceof PyClassLikeType) { diff --git a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java index eb72940388c1..bf4d2623b070 100644 --- a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java +++ b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java @@ -29,6 +29,7 @@ import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler; import com.intellij.usageView.UsageInfo; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyNames; +import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PythonFileType; import com.jetbrains.python.actions.CreatePackageAction; import com.jetbrains.python.codeInsight.imports.PyImportOptimizer; @@ -119,6 +120,7 @@ public class PyMoveFileHandler extends MoveFileHandler { continue; } final QualifiedName newElementName = QualifiedNameFinder.findCanonicalImportPath(newElement, element); + removeLeadingDots(element); replaceWithQualifiedExpression(element, newElementName); } else if (element instanceof PyReferenceExpression) { @@ -157,6 +159,23 @@ public class PyMoveFileHandler extends MoveFileHandler { return oldElement; } + private static void removeLeadingDots(@NotNull PsiElement element) { + PsiElement lastDot = null; + PsiElement firstDot = null; + for (PsiElement prev = element.getPrevSibling(); prev != null; prev = prev.getPrevSibling()) { + if (prev.getNode().getElementType() != PyTokenTypes.DOT) { + break; + } + if (lastDot == null) { + lastDot = prev; + } + firstDot = prev; + } + if (lastDot != null && firstDot != null) { + element.getParent().deleteChildRange(firstDot, lastDot); + } + } + @Override public void updateMovedFile(PsiFile file) throws IncorrectOperationException { } diff --git a/python/src/com/jetbrains/python/sdk/flavors/CPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/CPythonSdkFlavor.java index 62448004d574..da0f236205d0 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/CPythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/CPythonSdkFlavor.java @@ -17,10 +17,13 @@ package com.jetbrains.python.sdk.flavors; import org.jetbrains.annotations.NotNull; +import java.util.regex.Pattern; + /** * @author yole */ public abstract class CPythonSdkFlavor extends PythonSdkFlavor { + public final static Pattern PYTHON_RE = Pattern.compile("python-?(\\d\\.\\d)?|python-?(\\d)?"); @NotNull @Override public String getName() { diff --git a/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java index 05f7c28f849a..4cd9326ddc78 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java @@ -18,8 +18,10 @@ package com.jetbrains.python.sdk.flavors; import com.google.common.collect.Lists; import com.intellij.openapi.util.text.StringUtil; import com.intellij.remote.RemoteFile; +import icons.PythonIcons; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.util.Collection; /** @@ -40,7 +42,7 @@ public class PyRemoteSdkFlavor extends CPythonSdkFlavor { @Override public boolean isValidSdkHome(String path) { - return StringUtil.isNotEmpty(path) && path.startsWith("ssh:") && checkName(NAMES, getExecutableName(path)); + return StringUtil.isNotEmpty(path) && checkName(NAMES, getExecutableName(path)) && (path.startsWith("ssh:") || path.startsWith("vagrant:")); } private static boolean checkName(String[] names, @Nullable String name) { @@ -59,4 +61,9 @@ public class PyRemoteSdkFlavor extends CPythonSdkFlavor { private static String getExecutableName(String path) { return RemoteFile.createRemoteFile(path).getName(); } + + @Override + public Icon getIcon() { + return PythonIcons.Python.RemoteInterpreter; + } } diff --git a/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java index cf18921e017c..a424614d1338 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/UnixPythonSdkFlavor.java @@ -31,7 +31,7 @@ public class UnixPythonSdkFlavor extends CPythonSdkFlavor { private UnixPythonSdkFlavor() { } - private final static String[] NAMES = new String[]{"python", "jython", "pypy"}; + private final static String[] NAMES = new String[]{"jython", "pypy"}; public static UnixPythonSdkFlavor INSTANCE = new UnixPythonSdkFlavor(); @@ -52,9 +52,9 @@ public class UnixPythonSdkFlavor extends CPythonSdkFlavor { VirtualFile[] suspects = rootDir.getChildren(); for (VirtualFile child : suspects) { if (!child.isDirectory()) { - final String childName = child.getName(); + final String childName = child.getName().toLowerCase(); for (String name : NAMES) { - if (childName.startsWith(name)) { + if (childName.startsWith(name) || PYTHON_RE.matcher(childName).matches()) { String childPath = child.getPath(); if (FileSystemUtil.isSymLink(childPath)) { childPath = FileSystemUtil.resolveSymLink(childPath); diff --git a/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java index 576a66279900..7918f63ff77d 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/VirtualEnvSdkFlavor.java @@ -41,8 +41,7 @@ import java.util.List; public class VirtualEnvSdkFlavor extends CPythonSdkFlavor { private VirtualEnvSdkFlavor() { } - - private final static String[] NAMES = new String[]{"python", "jython", "pypy", "python.exe", "jython.bat", "pypy.exe"}; + private final static String[] NAMES = new String[]{"jython", "pypy", "python.exe", "jython.bat", "pypy.exe"}; public static VirtualEnvSdkFlavor INSTANCE = new VirtualEnvSdkFlavor(); @@ -107,7 +106,7 @@ public class VirtualEnvSdkFlavor extends CPythonSdkFlavor { private static String findInterpreter(VirtualFile dir) { for (VirtualFile child : dir.getChildren()) { if (!child.isDirectory()) { - final String childName = child.getName(); + final String childName = child.getName().toLowerCase(); for (String name : NAMES) { if (SystemInfo.isWindows) { if (childName.equals(name)) { @@ -115,7 +114,7 @@ public class VirtualEnvSdkFlavor extends CPythonSdkFlavor { } } else { - if (childName.startsWith(name)) { + if (childName.startsWith(name) || PYTHON_RE.matcher(childName).matches()) { if (!childName.endsWith("-config")) { return child.getPath(); } diff --git a/python/testData/codeInsight/smartEnter/comment.py b/python/testData/codeInsight/smartEnter/comment.py index c776b2a05afb..edf9e80daaf9 100644 --- a/python/testData/codeInsight/smartEnter/comment.py +++ b/python/testData/codeInsight/smartEnter/comment.py @@ -1 +1 @@ -#comment \ No newline at end of file +# comment \ No newline at end of file diff --git a/python/testData/codeInsight/smartEnter/comment_after.py b/python/testData/codeInsight/smartEnter/comment_after.py index 374c22d6a10a..129e53e20712 100644 --- a/python/testData/codeInsight/smartEnter/comment_after.py +++ b/python/testData/codeInsight/smartEnter/comment_after.py @@ -1,2 +1,2 @@ -#comment -# \ No newline at end of file +# comment +# \ No newline at end of file diff --git a/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment.py b/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment.py new file mode 100644 index 000000000000..d2f1f9bdb19d --- /dev/null +++ b/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment.py @@ -0,0 +1,2 @@ +# foo +pass \ No newline at end of file diff --git a/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment_after.py b/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment_after.py new file mode 100644 index 000000000000..9e0b9db075d8 --- /dev/null +++ b/python/testData/codeInsight/smartEnter/spaceInsertedAfterHashSignInComment_after.py @@ -0,0 +1,3 @@ +# foo +# +pass \ No newline at end of file diff --git a/python/testData/fillParagraph/emptyMultilineString.py b/python/testData/fillParagraph/emptyMultilineString.py new file mode 100644 index 000000000000..5180c20fbd92 --- /dev/null +++ b/python/testData/fillParagraph/emptyMultilineString.py @@ -0,0 +1,3 @@ +a = """ + +""" \ No newline at end of file diff --git a/python/testData/fillParagraph/emptyMultilineString_after.py b/python/testData/fillParagraph/emptyMultilineString_after.py new file mode 100644 index 000000000000..277257c94d71 --- /dev/null +++ b/python/testData/fillParagraph/emptyMultilineString_after.py @@ -0,0 +1,3 @@ +a = """ + +""" \ No newline at end of file diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/StubsOfNestedClasses/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection/StubsOfNestedClasses/a.py new file mode 100644 index 000000000000..855d14972ed6 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/StubsOfNestedClasses/a.py @@ -0,0 +1,10 @@ +from b import Class2 + + +class Class3(Class2): + class SubClass3(Class2.SubClass2): + def __init__(self, foo): + Class2.SubClass2.__init__(self, foo) + + def test(self): + print(self.foo) diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/StubsOfNestedClasses/b.py b/python/testData/inspections/PyUnresolvedReferencesInspection/StubsOfNestedClasses/b.py new file mode 100644 index 000000000000..4c33b9e5f340 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/StubsOfNestedClasses/b.py @@ -0,0 +1,8 @@ +from c import Class1 + + +class Class2(Class1): + class SubClass2(Class1.SubClass1): + def __init__(self, foo): + Class1.SubClass1.__init__(self, foo) + diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/StubsOfNestedClasses/c.py b/python/testData/inspections/PyUnresolvedReferencesInspection/StubsOfNestedClasses/c.py new file mode 100644 index 000000000000..e771f0bcc970 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/StubsOfNestedClasses/c.py @@ -0,0 +1,4 @@ +class Class1(object): + class SubClass1(object): + def __init__(self, foo=None): + self.foo = foo diff --git a/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/main.py b/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/main.py new file mode 100644 index 000000000000..b5e5da256cfa --- /dev/null +++ b/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/main.py @@ -0,0 +1 @@ +MyOldStyleClass diff --git a/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/module.py b/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/module.py new file mode 100644 index 000000000000..4652e3d0f87e --- /dev/null +++ b/python/testData/inspections/objectBaseIsNotShownInAutoImportQuickfix/module.py @@ -0,0 +1,2 @@ +class MyOldStyleClass: + pass diff --git a/python/testData/refactoring/move/relativeImportInsideNamespacePackage/after/src/nspkg/a.py b/python/testData/refactoring/move/relativeImportInsideNamespacePackage/after/src/nspkg/a.py new file mode 100644 index 000000000000..37fb8093807e --- /dev/null +++ b/python/testData/refactoring/move/relativeImportInsideNamespacePackage/after/src/nspkg/a.py @@ -0,0 +1,3 @@ +from nssubpkg import b + +print(b) \ No newline at end of file diff --git a/python/testData/refactoring/move/relativeImportInsideNamespacePackage/after/src/nssubpkg/b.py b/python/testData/refactoring/move/relativeImportInsideNamespacePackage/after/src/nssubpkg/b.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportInsideNamespacePackage/before/src/nspkg/a.py b/python/testData/refactoring/move/relativeImportInsideNamespacePackage/before/src/nspkg/a.py new file mode 100644 index 000000000000..c6af594436cf --- /dev/null +++ b/python/testData/refactoring/move/relativeImportInsideNamespacePackage/before/src/nspkg/a.py @@ -0,0 +1,3 @@ +from .nssubpkg import b + +print(b) \ No newline at end of file diff --git a/python/testData/refactoring/move/relativeImportInsideNamespacePackage/before/src/nspkg/nssubpkg/b.py b/python/testData/refactoring/move/relativeImportInsideNamespacePackage/before/src/nspkg/nssubpkg/b.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportInsideNormalPackage/after/src/nspkg/__init__.py b/python/testData/refactoring/move/relativeImportInsideNormalPackage/after/src/nspkg/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportInsideNormalPackage/after/src/nspkg/a.py b/python/testData/refactoring/move/relativeImportInsideNormalPackage/after/src/nspkg/a.py new file mode 100644 index 000000000000..37fb8093807e --- /dev/null +++ b/python/testData/refactoring/move/relativeImportInsideNormalPackage/after/src/nspkg/a.py @@ -0,0 +1,3 @@ +from nssubpkg import b + +print(b) \ No newline at end of file diff --git a/python/testData/refactoring/move/relativeImportInsideNormalPackage/after/src/nssubpkg/__init__.py b/python/testData/refactoring/move/relativeImportInsideNormalPackage/after/src/nssubpkg/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportInsideNormalPackage/after/src/nssubpkg/b.py b/python/testData/refactoring/move/relativeImportInsideNormalPackage/after/src/nssubpkg/b.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportInsideNormalPackage/before/src/nspkg/__init__.py b/python/testData/refactoring/move/relativeImportInsideNormalPackage/before/src/nspkg/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportInsideNormalPackage/before/src/nspkg/a.py b/python/testData/refactoring/move/relativeImportInsideNormalPackage/before/src/nspkg/a.py new file mode 100644 index 000000000000..c6af594436cf --- /dev/null +++ b/python/testData/refactoring/move/relativeImportInsideNormalPackage/before/src/nspkg/a.py @@ -0,0 +1,3 @@ +from .nssubpkg import b + +print(b) \ No newline at end of file diff --git a/python/testData/refactoring/move/relativeImportInsideNormalPackage/before/src/nspkg/nssubpkg/__init__.py b/python/testData/refactoring/move/relativeImportInsideNormalPackage/before/src/nspkg/nssubpkg/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportInsideNormalPackage/before/src/nspkg/nssubpkg/b.py b/python/testData/refactoring/move/relativeImportInsideNormalPackage/before/src/nspkg/nssubpkg/b.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportOfNameFromInitPy/after/src/pkg/__init__.py b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/after/src/pkg/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportOfNameFromInitPy/after/src/pkg/subpkg1/__init__.py b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/after/src/pkg/subpkg1/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportOfNameFromInitPy/after/src/pkg/subpkg1/a.py b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/after/src/pkg/subpkg1/a.py new file mode 100644 index 000000000000..a8a924147fe9 --- /dev/null +++ b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/after/src/pkg/subpkg1/a.py @@ -0,0 +1,3 @@ +from subpkg2 import VAR + +print(VAR) \ No newline at end of file diff --git a/python/testData/refactoring/move/relativeImportOfNameFromInitPy/after/src/subpkg2/__init__.py b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/after/src/subpkg2/__init__.py new file mode 100644 index 000000000000..0f1e78e3db76 --- /dev/null +++ b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/after/src/subpkg2/__init__.py @@ -0,0 +1 @@ +VAR = 'spam' \ No newline at end of file diff --git a/python/testData/refactoring/move/relativeImportOfNameFromInitPy/before/src/pkg/__init__.py b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/before/src/pkg/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportOfNameFromInitPy/before/src/pkg/subpkg1/__init__.py b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/before/src/pkg/subpkg1/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/relativeImportOfNameFromInitPy/before/src/pkg/subpkg1/a.py b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/before/src/pkg/subpkg1/a.py new file mode 100644 index 000000000000..82c613b49f17 --- /dev/null +++ b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/before/src/pkg/subpkg1/a.py @@ -0,0 +1,3 @@ +from ..subpkg2 import VAR + +print(VAR) \ No newline at end of file diff --git a/python/testData/refactoring/move/relativeImportOfNameFromInitPy/before/src/pkg/subpkg2/__init__.py b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/before/src/pkg/subpkg2/__init__.py new file mode 100644 index 000000000000..0f1e78e3db76 --- /dev/null +++ b/python/testData/refactoring/move/relativeImportOfNameFromInitPy/before/src/pkg/subpkg2/__init__.py @@ -0,0 +1 @@ +VAR = 'spam' \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyFillParagraphTest.java b/python/testSrc/com/jetbrains/python/PyFillParagraphTest.java index 287c65f9e8a1..0fd99a9772b7 100644 --- a/python/testSrc/com/jetbrains/python/PyFillParagraphTest.java +++ b/python/testSrc/com/jetbrains/python/PyFillParagraphTest.java @@ -20,7 +20,6 @@ import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.command.CommandProcessor; -import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.jetbrains.python.fixtures.PyTestCase; @@ -62,6 +61,10 @@ public class PyFillParagraphTest extends PyTestCase { doTest(); } + public void testEmptyMultilineString() { + doTest(); + } + public void testEnter() { final CommonCodeStyleSettings settings = CodeStyleSettingsManager.getInstance(myFixture.getProject()).getCurrentSettings().getCommonSettings(PythonLanguage.getInstance()); diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index 6cc2e578fb30..4b9b5ca42e0c 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -50,6 +50,16 @@ public class PyQuickFixTest extends PyTestCase { PyUnresolvedReferencesInspection.class, "Import 'importFromModule.foo.baz'", true, true); } + // PY-14365 + public void testObjectBaseIsNotShownInAutoImportQuickfix() { + myFixture.copyDirectoryToProject("objectBaseIsNotShownInAutoImportQuickfix", ""); + myFixture.configureByFile("main.py"); + myFixture.enableInspections(PyUnresolvedReferencesInspection.class); + final IntentionAction intention = myFixture.findSingleIntention("Import"); + assertNotNull(intention); + assertEquals("Import 'module.MyOldStyleClass'", intention.getText()); + } + public void testImportFromModuleStar() { // PY-6302 myFixture.enableInspections(PyUnresolvedReferencesInspection.class); myFixture.copyDirectoryToProject("importFromModuleStar", ""); diff --git a/python/testSrc/com/jetbrains/python/PySmartEnterTest.java b/python/testSrc/com/jetbrains/python/PySmartEnterTest.java index e58988010645..a4db79654658 100644 --- a/python/testSrc/com/jetbrains/python/PySmartEnterTest.java +++ b/python/testSrc/com/jetbrains/python/PySmartEnterTest.java @@ -189,4 +189,9 @@ public class PySmartEnterTest extends PyTestCase { public void testWithOnlyColonMissing() { doTest(); } + + // PY-9209 + public void testSpaceInsertedAfterHashSignInComment() { + doTest(); + } } diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 88b036bac86e..98c8674e1793 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -415,6 +415,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doMultiFileTest(); } + // PY-13969 + public void testStubsOfNestedClasses() { + doMultiFileTest(); + } + @NotNull @Override protected Class getInspectionClass() { diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java index 0e1a673b3e7f..2622ccf8c6e8 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java @@ -174,6 +174,24 @@ public class PyMoveTest extends PyTestCase { }); } + // PY-14384 + public void testRelativeImportInsideNamespacePackage() { + runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() { + @Override + public void run() { + doMoveFileTest("nspkg/nssubpkg", ""); + } + }); + } + + // PY-14384 + public void testRelativeImportInsideNormalPackage() { + doMoveFileTest("nspkg/nssubpkg", ""); + } + + public void testRelativeImportOfNameFromInitPy() { + doMoveFileTest("pkg/subpkg2", ""); + } private void doMoveFileTest(String fileName, String toDirName) { Project project = myFixture.getProject(); diff --git a/xml/xml-psi-impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java b/xml/xml-psi-impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java index 1de12639ca1a..c8cba3f84d0e 100644 --- a/xml/xml-psi-impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java +++ b/xml/xml-psi-impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java @@ -36,7 +36,7 @@ public class RelaxedHtmlFromSchemaElementDescriptor extends XmlElementDescriptor } public static XmlAttributeDescriptor[] getCommonAttributeDescriptors(XmlTag context) { - final XmlNSDescriptor nsDescriptor = context != null ? context.getNSDescriptor("", false) : null; + final XmlNSDescriptor nsDescriptor = context != null ? context.getNSDescriptor(context.getNamespace(), false) : null; if (nsDescriptor != null) { for (XmlElementDescriptor descriptor : nsDescriptor.getRootElementsDescriptors(null)) { final String name = descriptor.getName();