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 ca27c8d0e4a0..c6bb0fc2d738 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 @@ -119,14 +119,14 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { @Override public void visitErrorElement(PsiErrorElement element) { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", element.getText())); + throwExpressionInvalid(element); } @Override public void visitAssignmentExpression(PsiAssignmentExpression expression) { final PsiExpression rExpression = expression.getRExpression(); if(rExpression == null) { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return; + throwExpressionInvalid(expression); } rExpression.accept(this); @@ -344,8 +344,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { for (int i = 1; i < operands.length; i++) { PsiExpression expression = operands[i]; if (expression == null) { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", wideExpression.getText())); - return; + throwExpressionInvalid(wideExpression); } expression.accept(this); Evaluator rResult = myResult; @@ -585,22 +584,22 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { final PsiExpression thenExpression = expression.getThenExpression(); final PsiExpression elseExpression = expression.getElseExpression(); if (thenExpression == null || elseExpression == null){ - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return; + throwExpressionInvalid(expression); } PsiExpression condition = expression.getCondition(); condition.accept(this); if (myResult == null) { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", condition.getText())); return; + throwExpressionInvalid(condition); } Evaluator conditionEvaluator = new UnBoxingEvaluator(myResult); thenExpression.accept(this); if (myResult == null) { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", thenExpression.getText())); return; + throwExpressionInvalid(thenExpression); } Evaluator thenEvaluator = myResult; elseExpression.accept(this); if (myResult == null) { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", elseExpression.getText())); return; + throwExpressionInvalid(elseExpression); } Evaluator elseEvaluator = myResult; myResult = new ConditionalExpressionEvaluator(conditionEvaluator, thenEvaluator, elseEvaluator); @@ -743,8 +742,11 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { } } + private static void throwExpressionInvalid(PsiElement expression) { + throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); + } + private static void throwEvaluateException(String message) throws EvaluateRuntimeException { - //noinspection ThrowableResultOfMethodCallIgnored throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(message)); } @@ -799,8 +801,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { } PsiTypeElement checkType = expression.getCheckType(); if(checkType == null) { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); - return; + throwExpressionInvalid(expression); } PsiType type = checkType.getType(); expression.getOperand().accept(this); @@ -910,7 +911,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { psiExpression.accept(this); if (myResult == null) { // cannot build evaluator - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", psiExpression.getText())); + throwExpressionInvalid(psiExpression); } argumentEvaluators[idx] = new DisableGC(myResult); } @@ -982,7 +983,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { } if (objectEvaluator == null) { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); + throwExpressionInvalid(expression); } if (psiMethod != null && !psiMethod.isConstructor()) { @@ -1027,7 +1028,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { public void visitArrayAccessExpression(PsiArrayAccessExpression expression) { final PsiExpression indexExpression = expression.getIndexExpression(); if(indexExpression == null) { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return; + throwExpressionInvalid(expression); } indexExpression.accept(this); final Evaluator indexEvaluator = handleUnaryNumericPromotion(indexExpression.getType(), myResult); @@ -1064,24 +1065,32 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { return operandEvaluator; } - @SuppressWarnings({"ConstantConditions"}) @Override public void visitTypeCastExpression(PsiTypeCastExpression expression) { - final PsiExpression operandExpr = expression.getOperand(); + PsiExpression operandExpr = expression.getOperand(); + if (operandExpr == null) { + throwExpressionInvalid(expression); + } operandExpr.accept(this); Evaluator operandEvaluator = myResult; - final PsiType castType = expression.getCastType().getType(); - final PsiType operandType = operandExpr.getType(); + PsiTypeElement castTypeElem = expression.getCastType(); + if (castTypeElem == null) { + throwExpressionInvalid(expression); + } + PsiType castType = castTypeElem.getType(); + PsiType operandType = operandExpr.getType(); // if operand type can not be resolved in current context - leave it for runtime checks - if (castType != null && operandType != null && !TypeConversionUtil.areTypesConvertible(operandType, castType) && PsiUtil.resolveClassInType(operandType) != null) { + if (operandType != null && + !TypeConversionUtil.areTypesConvertible(operandType, castType) && + PsiUtil.resolveClassInType(operandType) != null) { throw new EvaluateRuntimeException( new EvaluateException(JavaErrorMessages.message("inconvertible.type.cast", JavaHighlightUtil.formatType(operandType), JavaHighlightUtil .formatType(castType))) ); } - final boolean shouldPerformBoxingConversion = castType != null && operandType != null && TypeConversionUtil.boxingConversionApplicable(castType, operandType); + boolean shouldPerformBoxingConversion = operandType != null && TypeConversionUtil.boxingConversionApplicable(castType, operandType); final boolean castingToPrimitive = castType instanceof PsiPrimitiveType; if (shouldPerformBoxingConversion && castingToPrimitive) { operandEvaluator = new UnBoxingEvaluator(operandEvaluator); @@ -1154,14 +1163,14 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer(); if (arrayInitializer != null) { if (dimensionEvaluator != null) { // initializer already exists - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); + throwExpressionInvalid(expression); } arrayInitializer.accept(this); if (myResult != null) { initializerEvaluator = handleUnaryNumericPromotion(arrayInitializer.getType(), myResult); } else { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", arrayInitializer.getText())); + throwExpressionInvalid(arrayInitializer); } /* PsiExpression[] initializers = arrayInitializer.getInitializers(); @@ -1179,7 +1188,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { */ } if (dimensionEvaluator == null && initializerEvaluator == null) { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); + throwExpressionInvalid(expression); } myResult = new NewArrayInstanceEvaluator( new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(expressionPsiType)), @@ -1194,7 +1203,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { } PsiExpressionList argumentList = expression.getArgumentList(); if (argumentList == null) { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return; + throwExpressionInvalid(expression); } final PsiExpression[] argExpressions = argumentList.getExpressions(); final JavaResolveResult constructorResolveResult = expression.resolveMethodGenerics(); @@ -1212,7 +1221,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { argumentEvaluators[idx] = new DisableGC(myResult); } else { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", argExpression.getText())); + throwExpressionInvalid(argExpression); } } @@ -1265,7 +1274,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { evaluators[idx] = new DisableGC(coerced); } else { - throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", initializer.getText())); + throwExpressionInvalid(initializer); } } myResult = new ArrayInitializerEvaluator(evaluators); diff --git a/java/execution/impl/src/com/intellij/execution/actions/AbstractAddToTestsPatternAction.java b/java/execution/impl/src/com/intellij/execution/actions/AbstractAddToTestsPatternAction.java index 1c5765a39650..851bdf322343 100644 --- a/java/execution/impl/src/com/intellij/execution/actions/AbstractAddToTestsPatternAction.java +++ b/java/execution/impl/src/com/intellij/execution/actions/AbstractAddToTestsPatternAction.java @@ -26,12 +26,11 @@ import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.PopupStep; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.psi.PsiElement; +import com.intellij.psi.search.PsiElementProcessor; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; public abstract class AbstractAddToTestsPatternAction extends AnAction { @NotNull protected abstract AbstractPatternBasedConfigurationProducer getPatternBasedProducer(); @@ -46,7 +45,9 @@ public abstract class AbstractAddToTestsPatternAction classes = getPatternBasedProducer().collectTestMembers(psiElements, true); + final LinkedHashSet classes = new LinkedHashSet(); + PsiElementProcessor.CollectElements processor = new PsiElementProcessor.CollectElements(classes); + getPatternBasedProducer().collectTestMembers(psiElements, true, true, processor); final Project project = CommonDataKeys.PROJECT.getData(dataContext); final List patternConfigurations = collectPatternConfigurations(classes, project); @@ -86,11 +87,13 @@ public abstract class AbstractAddToTestsPatternAction foundMembers = getPatternBasedProducer().collectTestMembers(psiElements, true); - if (foundMembers.isEmpty()) return; + PsiElementProcessor.CollectElementsWithLimit processor = new PsiElementProcessor.CollectElementsWithLimit(2); + getPatternBasedProducer().collectTestMembers(psiElements, false, false, processor); + Collection collection = processor.getCollection(); + if (collection.isEmpty()) return; final Project project = CommonDataKeys.PROJECT.getData(dataContext); if (project != null) { - final List foundConfigurations = collectPatternConfigurations(foundMembers, project); + final List foundConfigurations = collectPatternConfigurations(collection, project); if (!foundConfigurations.isEmpty()) { presentation.setVisible(true); if (foundConfigurations.size() == 1) { @@ -101,7 +104,7 @@ public abstract class AbstractAddToTestsPatternAction collectPatternConfigurations(Set foundClasses, Project project) { + private List collectPatternConfigurations(Collection foundClasses, Project project) { final List configurations = RunManager.getInstance(project).getConfigurationsList(getConfigurationType()); final List foundConfigurations = new ArrayList(); for (RunConfiguration configuration : configurations) { diff --git a/java/execution/impl/src/com/intellij/execution/testframework/AbstractPatternBasedConfigurationProducer.java b/java/execution/impl/src/com/intellij/execution/testframework/AbstractPatternBasedConfigurationProducer.java index 12a0502e31a6..b1186ab0efc3 100644 --- a/java/execution/impl/src/com/intellij/execution/testframework/AbstractPatternBasedConfigurationProducer.java +++ b/java/execution/impl/src/com/intellij/execution/testframework/AbstractPatternBasedConfigurationProducer.java @@ -26,10 +26,12 @@ import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.util.ClassUtil; import java.util.ArrayList; @@ -55,18 +57,27 @@ public abstract class AbstractPatternBasedConfigurationProducer classes = new LinkedHashSet(); - final PsiElement[] elements = collectPatternElements(context, classes); - if (elements != null && collectTestMembers(elements, false).size() > 1) { - return true; + final PsiElementProcessor.CollectElementsWithLimit processor = new PsiElementProcessor.CollectElementsWithLimit(2); + final PsiElement[] locationElements = collectLocationElements(classes, dataContext); + if (locationElements != null) { + collectTestMembers(locationElements, false, false, processor); } - return false; + else { + collectContextElements(dataContext, false, false, classes, processor); + } + return processor.getCollection().size() > 1; } public boolean isConfiguredFromContext(ConfigurationContext context, Set patterns) { final LinkedHashSet classes = new LinkedHashSet(); - collectPatternElements(context, classes); + final DataContext dataContext = context.getDataContext(); + final PsiElement[] locationElements = collectLocationElements(classes, dataContext); + if (locationElements == null) { + collectContextElements(dataContext, true, false, classes, new PsiElementProcessor.CollectElements()); + } if (Comparing.equal(classes, patterns)) { return true; } @@ -74,43 +85,91 @@ public abstract class AbstractPatternBasedConfigurationProducer classes) { - PsiElement[] elements = collectPatternElements(context, classes); - if (elements == null || collectTestMembers(elements, false).size() <= 1) { + PsiElement[] result; + final DataContext dataContext = context.getDataContext(); + final PsiElement[] locationElements = collectLocationElements(classes, dataContext); + PsiElementProcessor.CollectElements processor = new PsiElementProcessor.CollectElements(); + if (locationElements != null) { + collectTestMembers(locationElements, false, true, processor); + result = processor.toArray(); + } + else if (collectContextElements(dataContext, true, true, classes, processor)) { + result = processor.toArray(); + } + else { return null; } - return elements[0]; + if (result.length <= 1) { + return null; + } + return result[0]; } - public Set collectTestMembers(PsiElement[] psiElements, boolean checkAbstract) { - final Set foundMembers = new LinkedHashSet(); + public void collectTestMembers(PsiElement[] psiElements, + boolean checkAbstract, + boolean checkIsTest, + PsiElementProcessor.CollectElements collectingProcessor) { for (PsiElement psiElement : psiElements) { if (psiElement instanceof PsiClassOwner) { final PsiClass[] classes = ((PsiClassOwner)psiElement).getClasses(); for (PsiClass aClass : classes) { - if (isTestClass(aClass)) { - foundMembers.add(aClass); + if ((!checkIsTest || isTestClass(aClass)) && !collectingProcessor.execute(aClass)) { + return; } } } else if (psiElement instanceof PsiClass) { - if (isTestClass((PsiClass)psiElement)) { - foundMembers.add(psiElement); + if ((!checkIsTest || isTestClass((PsiClass)psiElement)) && !collectingProcessor.execute(psiElement)) { + return; } } else if (psiElement instanceof PsiMethod) { - if (isTestMethod(checkAbstract, psiElement)) { - foundMembers.add(psiElement); + if ((!checkIsTest || isTestMethod(checkAbstract, psiElement)) && !collectingProcessor.execute(psiElement)) { + return; } } else if (psiElement instanceof PsiDirectory) { final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage((PsiDirectory)psiElement); - if (aPackage != null) { - foundMembers.add(aPackage); + if (aPackage != null && !collectingProcessor.execute(aPackage)) { + return; } } } - return foundMembers; } - - private PsiElement[] collectPatternElements(ConfigurationContext context, LinkedHashSet classes) { - final DataContext dataContext = context.getDataContext(); + + private boolean collectContextElements(DataContext dataContext, + boolean checkAbstract, + boolean checkIsTest, + LinkedHashSet classes, + PsiElementProcessor.CollectElements processor) { + PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext); + if (elements != null) { + collectTestMembers(elements, checkAbstract, checkIsTest, processor); + for (PsiElement psiClass : processor.getCollection()) { + classes.add(getQName(psiClass)); + } + return true; + } + else { + final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext); + if (files != null) { + Project project = CommonDataKeys.PROJECT.getData(dataContext); + if (project != null) { + final PsiManager psiManager = PsiManager.getInstance(project); + for (VirtualFile file : files) { + final PsiFile psiFile = psiManager.findFile(file); + if (psiFile instanceof PsiClassOwner) { + collectTestMembers(((PsiClassOwner)psiFile).getClasses(), checkAbstract, checkIsTest, processor); + for (PsiElement psiMember : processor.getCollection()) { + classes.add(((PsiClass)psiMember).getQualifiedName()); + } + } + } + return true; + } + } + } + return false; + } + + private static PsiElement[] collectLocationElements(LinkedHashSet classes, DataContext dataContext) { final Location[] locations = Location.DATA_KEYS.getData(dataContext); if (locations != null) { List elements = new ArrayList(); @@ -121,29 +180,6 @@ public abstract class AbstractPatternBasedConfigurationProducer psiFiles = new ArrayList(); - final PsiManager psiManager = PsiManager.getInstance(context.getProject()); - for (VirtualFile file : files) { - final PsiFile psiFile = psiManager.findFile(file); - if (psiFile instanceof PsiClassOwner) { - for (PsiElement psiMember : collectTestMembers(((PsiClassOwner)psiFile).getClasses(), true)) { - classes.add(((PsiClass)psiMember).getQualifiedName()); - } - psiFiles.add(psiFile); - } - } - return psiFiles.toArray(new PsiElement[psiFiles.size()]); - } - } return null; } diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java index b6dcb69ea76f..9a7d7bc32d51 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java @@ -767,4 +767,20 @@ public class SmartPsiElementPointersTest extends CodeInsightTestCase { assertNotNull(pointer.getElement()); } + + public void testPointerToEmptyElement() { + PsiFile file = configureByText(JavaFileType.INSTANCE, "class Foo {\n" + + " Test test = new Test<>();\n" + + "}"); + PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset(file, file.getText().indexOf("<>"), PsiJavaCodeReferenceElement.class, false); + SmartPointerEx pointer = (SmartPointerEx)SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer( + ref.getParameterList().getTypeParameterElements()[0]); + ref = null; + + PlatformTestUtil.tryGcSoftlyReachableObjects(); + assertNull(pointer.getCachedElement()); + + assertInstanceOf(pointer.getElement(), PsiTypeElement.class); + } + } diff --git a/platform/analysis-api/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java b/platform/analysis-api/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java index 779910576f5f..d6df865c7130 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java @@ -60,13 +60,9 @@ public abstract class InspectionToolWrapper other) { myEP = other.myEP; // we need to create a copy for buffering - if (myEP != null) { + if (other.myTool != null) { //noinspection unchecked - myTool = (T)myEP.instantiateTool(); - } - else if (other.myTool != null) { - //noinspection unchecked - myTool = (T)InspectionToolsRegistrarCore.instantiateTool(other.myTool.getClass()); + myTool = myEP != null ? (T)myEP.instantiateTool() : (T)InspectionToolsRegistrarCore.instantiateTool(other.myTool.getClass()); } else { myTool = null; diff --git a/platform/core-api/src/com/intellij/psi/SyntaxTraverser.java b/platform/core-api/src/com/intellij/psi/SyntaxTraverser.java index cff07563ccaa..5631b311d636 100644 --- a/platform/core-api/src/com/intellij/psi/SyntaxTraverser.java +++ b/platform/core-api/src/com/intellij/psi/SyntaxTraverser.java @@ -70,7 +70,7 @@ public class SyntaxTraverser extends FilteredTraverserBase lightTraverser(@NotNull PsiBuilder builder) { LighterASTApi api = new LighterASTApi(builder); - return new SyntaxTraverser(api, Meta.empty().withRoots(JBIterable.of(api.flyweightStructure.getRoot()))); + return new SyntaxTraverser(api, Meta.empty().withRoots(JBIterable.of(api.getStructure().getRoot()))); } public final Api api; @@ -363,16 +363,14 @@ public class SyntaxTraverser extends FilteredTraverserBase extends Api { - final FlyweightCapableTreeStructure flyweightStructure; - public FlyweightApi(@NotNull FlyweightCapableTreeStructure structure) { - flyweightStructure = structure; - } + @NotNull + abstract FlyweightCapableTreeStructure getStructure(); @Nullable @Override public T parent(@NotNull T node) { - return flyweightStructure.getParent(node); + return getStructure().getParent(node); } @NotNull @@ -381,8 +379,9 @@ public class SyntaxTraverser extends FilteredTraverserBase() { @Override public Iterator iterator() { + FlyweightCapableTreeStructure structure = getStructure(); Ref ref = Ref.create(); - int count = flyweightStructure.getChildren(flyweightStructure.prepareForGetChildren(node), ref); + int count = structure.getChildren(structure.prepareForGetChildren(node), ref); if (count == 0) return ContainerUtil.emptyIterator(); T[] array = ref.get(); LinkedList list = ContainerUtil.newLinkedList(); @@ -399,7 +398,7 @@ public class SyntaxTraverser extends FilteredTraverserBase extends FilteredTraverserBase { private final PsiBuilder builder; + private final ThreadLocalCachedValue> structure = + new ThreadLocalCachedValue>() { + @Override + protected FlyweightCapableTreeStructure create() { + return builder.getLightTree(); + } + }; - public LighterASTApi(PsiBuilder builder) { - super(builder.getLightTree()); + public LighterASTApi(final PsiBuilder builder) { this.builder = builder; } + @NotNull + @Override + FlyweightCapableTreeStructure getStructure() { + return structure.getValue(); + } + @NotNull @Override public IElementType typeOf(@NotNull LighterASTNode node) { diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java index b4a686fe29bd..4f0896755954 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java @@ -26,6 +26,7 @@ import com.intellij.openapi.util.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.PsiDocumentManagerBase; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -133,6 +134,18 @@ public class SelfElementInfo extends SmartPointerElementInfo { PsiElement anchor = file.getViewProvider().findElementAt(syncStartOffset, language); if (anchor == null) return null; + PsiElement result = findParent(syncStartOffset, syncEndOffset, type, anchor); + if (result == null && syncEndOffset == syncStartOffset && anchor.getTextRange().getStartOffset() == syncEndOffset) { + anchor = PsiTreeUtil.prevLeaf(anchor, false); + if (anchor != null) { + result = findParent(syncStartOffset, syncEndOffset, type, anchor); + } + } + return result; + } + + @Nullable + private static PsiElement findParent(int syncStartOffset, int syncEndOffset, @NotNull Class type, PsiElement anchor) { TextRange range = anchor.getTextRange(); if (range.getStartOffset() != syncStartOffset) return null; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java index 54b85bbaab06..0662ee4a6cd1 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java @@ -16,23 +16,20 @@ package com.intellij.codeInsight.intention.impl; import com.intellij.codeInsight.editorActions.CopyPastePreProcessor; -import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.codeInsight.template.TemplateManager; import com.intellij.injected.editor.DocumentWindow; import com.intellij.lang.Language; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonShortcuts; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.editor.*; -import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.editor.actionSystem.EditorActionManager; import com.intellij.openapi.editor.actionSystem.ReadonlyFragmentModificationHandler; import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.editor.event.EditorFactoryAdapter; -import com.intellij.openapi.editor.event.EditorFactoryEvent; import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.FileEditor; @@ -41,7 +38,6 @@ import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.fileEditor.impl.EditorWindow; import com.intellij.openapi.fileEditor.impl.EditorWithProviderComposite; -import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.Balloon; @@ -138,46 +134,6 @@ public class QuickEditHandler extends DocumentAdapter implements Disposable { myOrigCreationStamp = myOrigDocument.getModificationStamp(); // store creation stamp for UNDO tracking myOrigDocument.addDocumentListener(this, this); myNewDocument.addDocumentListener(this, this); - EditorFactory editorFactory = ObjectUtils.assertNotNull(EditorFactory.getInstance()); - // not FileEditorManager listener because of RegExp checker and alike - editorFactory.addEditorFactoryListener(new EditorFactoryAdapter() { - - int myEditorCount; - - @Override - public void editorCreated(@NotNull EditorFactoryEvent event) { - if (event.getEditor().getDocument() != myNewDocument) return; - myEditorCount ++; - final EditorActionHandler editorEscape = EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_ESCAPE); - if (!myAction.isShowInBalloon()) { - new AnAction() { - @Override - public void update(AnActionEvent e) { - Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext()); - e.getPresentation().setEnabled( - editor != null && LookupManager.getActiveLookup(editor) == null && - TemplateManager.getInstance(myProject).getActiveTemplate(editor) == null && - (editorEscape == null || !editorEscape.isEnabled(editor, e.getDataContext()))); - } - - @Override - public void actionPerformed(AnActionEvent e) { - closeEditor(); - } - }.registerCustomShortcutSet(CommonShortcuts.ESCAPE, event.getEditor().getContentComponent()); - } - } - - @Override - public void editorReleased(@NotNull EditorFactoryEvent event) { - if (event.getEditor().getDocument() != myNewDocument) return; - if (-- myEditorCount > 0) return; - - if (Boolean.TRUE.equals(myNewVirtualFile.getUserData(FileEditorManagerImpl.CLOSING_TO_REOPEN))) return; - - Disposer.dispose(QuickEditHandler.this); - } - }, this); if ("JAVA".equals(firstShred.getHost().getLanguage().getID())) { PsiLanguageInjectionHost.Shred lastShred = ContainerUtil.getLastItem(shreds); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/LongLineInspection.java b/platform/lang-impl/src/com/intellij/codeInspection/LongLineInspection.java index cacf3f549a36..e221a9a76fa2 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/LongLineInspection.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/LongLineInspection.java @@ -17,12 +17,15 @@ package com.intellij.codeInspection; import com.intellij.application.options.CodeStyleSchemesConfigurable; import com.intellij.ide.DataManager; +import com.intellij.injected.editor.VirtualFileWindow; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.options.ex.Settings; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.ui.HyperlinkLabel; @@ -77,8 +80,11 @@ public class LongLineInspection extends LocalInspectionTool { public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) { final Project project = manager.getProject(); final int codeStyleRightMargin = CodeStyleSettingsManager.getSettings(project).getRightMargin(file.getLanguage()); - final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project); - final Document document = psiDocumentManager.getDocument(file); + final VirtualFile vFile = file.getVirtualFile(); + if (vFile instanceof VirtualFileWindow) { + return null; + } + final Document document = FileDocumentManager.getInstance().getDocument(vFile); if (document == null) { return null; } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index 034b194437ec..78a5b29bc6c0 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -80,7 +80,9 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.datatransfer.DataFlavor; -import java.awt.event.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; import java.io.IOException; import java.util.*; import java.util.List; @@ -524,29 +526,25 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo myEditor = createConsoleEditor(); registerConsoleEditorActions(); myEditor.getScrollPane().setBorder(null); - myEditor.getScrollPane().addMouseWheelListener(new MouseWheelListener() { + MouseAdapter mouseListener = new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + updateStickToEndState(true); + } + + @Override + public void mouseDragged(MouseEvent e) { + updateStickToEndState(false); + } + @Override public void mouseWheelMoved(MouseWheelEvent e) { - if (e.getWheelRotation() < 0) { - myCancelStickToEnd = true; - } + updateStickToEndState(false); } - }); - myEditor.getScrollPane().getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() { - @Override - public void adjustmentValueChanged(AdjustmentEvent e) { - Adjustable scrollBar = e.getAdjustable(); - boolean vscrollAtBottom = scrollBar.getValue() == scrollBar.getMaximum() - scrollBar.getVisibleAmount(); - - if (e.getValueIsAdjusting()) { - myCancelStickToEnd = !vscrollAtBottom; - } - - if (vscrollAtBottom && !isStickingToEnd()) { - scrollToEnd(); - } - } - }); + }; + myEditor.getScrollPane().addMouseWheelListener(mouseListener); + myEditor.getScrollPane().getVerticalScrollBar().addMouseListener(mouseListener); + myEditor.getScrollPane().getVerticalScrollBar().addMouseMotionListener(mouseListener); myHyperlinks = new EditorHyperlinkSupport(myEditor, myProject); myEditor.getScrollingModel().addVisibleAreaListener(new VisibleAreaListener() { @Override @@ -565,6 +563,22 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo }); } + private void updateStickToEndState(boolean useImmediatePosition) { + if (myEditor == null) return; + + JScrollBar scrollBar = myEditor.getScrollPane().getVerticalScrollBar(); + int scrollBarPosition = useImmediatePosition ? scrollBar.getValue() : + myEditor.getScrollingModel().getVisibleAreaOnScrollingFinished().y; + boolean vscrollAtBottom = scrollBarPosition == scrollBar.getMaximum() - scrollBar.getVisibleAmount(); + boolean stickingToEnd = isStickingToEnd(); + + if (!vscrollAtBottom && stickingToEnd) { + myCancelStickToEnd = true; + } else if (vscrollAtBottom && !stickingToEnd) { + scrollToEnd(); + } + } + protected JComponent createCenterComponent() { return myEditor.getComponent(); } diff --git a/platform/lang-impl/src/com/intellij/openapi/vfs/encoding/FileEncodingConfigurable.java b/platform/lang-impl/src/com/intellij/openapi/vfs/encoding/FileEncodingConfigurable.java index 775cf1eea0b0..ce348e0d8070 100644 --- a/platform/lang-impl/src/com/intellij/openapi/vfs/encoding/FileEncodingConfigurable.java +++ b/platform/lang-impl/src/com/intellij/openapi/vfs/encoding/FileEncodingConfigurable.java @@ -196,7 +196,7 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Configu mySelectedCharsetForPropertiesFiles.set(encodingManager.getDefaultCharsetForPropertiesFiles(null)); mySelectedIdeCharset.set(EncodingManager.getInstance().getDefaultCharsetName().isEmpty() ? null : EncodingManager.getInstance().getDefaultCharset()); - mySelectedProjectCharset.set(EncodingProjectManager.getInstance(myProject).getDefaultCharsetName().isEmpty() ? null : EncodingProjectManager.getInstance(myProject).getDefaultCharset()); + mySelectedProjectCharset.set(encodingManager.getDefaultCharsetName().isEmpty() ? null : encodingManager.getDefaultCharset()); myPropertiesEncodingAction.update(null); myIdeEncodingAction.update(null); myProjectEncodingAction.update(null); diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionsFilter.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionsFilter.java index e80c357c1202..2e873bec81cc 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionsFilter.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionsFilter.java @@ -117,7 +117,7 @@ public abstract class InspectionsFilter { return false; } - if (myAvailableOnlyForAnalyze != isAvailableOnlyForAnalyze(tools)) { + if (myAvailableOnlyForAnalyze && !isAvailableOnlyForAnalyze(tools)) { return false; } diff --git a/platform/lang-impl/testSources/com/intellij/codeInspection/LongLineInspectionTest.java b/platform/lang-impl/testSources/com/intellij/codeInspection/LongLineInspectionTest.java index 3e6a2ffbf7d5..a76eafa74c83 100644 --- a/platform/lang-impl/testSources/com/intellij/codeInspection/LongLineInspectionTest.java +++ b/platform/lang-impl/testSources/com/intellij/codeInspection/LongLineInspectionTest.java @@ -31,7 +31,7 @@ public class LongLineInspectionTest extends LightPlatformCodeInsightFixtureTestC doTest("java"); } - public void testLongLine() { + public void _testLongLine() { doTest("java"); } diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index b53c1a6cd250..2bcc4c3e5314 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -121,9 +121,9 @@ public class IdeEventQueue extends EventQueue { */ private int myEventCount; - private boolean myIsInInputEvent = false; + private boolean myIsInInputEvent; - private AWTEvent myCurrentEvent = null; + private AWTEvent myCurrentEvent; private long myLastActiveTime; @@ -156,7 +156,7 @@ public class IdeEventQueue extends EventQueue { keyboardFocusManager.addPropertyChangeListener("permanentFocusOwner", new PropertyChangeListener() { @Override - public void propertyChange(final PropertyChangeEvent e) { + public void propertyChange(@NotNull final PropertyChangeEvent e) { final Application application = ApplicationManager.getApplication(); if (application == null) { // We can get focus event before application is initialized @@ -324,8 +324,8 @@ public class IdeEventQueue extends EventQueue { private static class InertialMouseRouter { private static final int MOUSE_WHEEL_RESTART_THRESHOLD = 50; - private static Component wheelDestinationComponent = null; - private static long lastMouseWheel = 0; + private static Component wheelDestinationComponent; + private static long lastMouseWheel; private static AWTEvent changeSourceIfNeeded(AWTEvent awtEvent) { if (SystemInfo.isMac && Registry.is("ide.inertial.mouse.fix") && awtEvent instanceof MouseWheelEvent) { @@ -342,7 +342,7 @@ public class IdeEventQueue extends EventQueue { } } - private static boolean ourAppIsLoaded = false; + private static boolean ourAppIsLoaded; private static boolean appIsLoaded() { if (ourAppIsLoaded) return true; @@ -352,7 +352,7 @@ public class IdeEventQueue extends EventQueue { } @Override - public void dispatchEvent(AWTEvent e) { + public void dispatchEvent(@NotNull AWTEvent e) { if (!appIsLoaded()) { try { super.dispatchEvent(e); @@ -400,8 +400,8 @@ public class IdeEventQueue extends EventQueue { } } - private static int ctrlIsPressedCount = 0; - private static boolean leftAltIsPressed = false; + private static int ctrlIsPressedCount; + private static boolean leftAltIsPressed; //private static boolean altGrIsPressed = false; private static AWTEvent fixNonEnglishKeyboardLayouts(AWTEvent e) { @@ -417,12 +417,12 @@ public class IdeEventQueue extends EventQueue { if (ke.getID() == KeyEvent.KEY_PRESSED) { switch (ke.getKeyCode()) { - case (KeyEvent.VK_CONTROL): + case KeyEvent.VK_CONTROL: if ((ke.getModifiersEx() & (InputEvent.ALT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)) != (InputEvent.ALT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)) { ctrlIsPressedCount++; } break; - case (KeyEvent.VK_ALT): + case KeyEvent.VK_ALT: if (ke.getKeyLocation() == KeyEvent.KEY_LOCATION_LEFT) { if ((ke.getModifiersEx() & (InputEvent.ALT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)) != (InputEvent.ALT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK)) { leftAltIsPressed = true; @@ -433,10 +433,10 @@ public class IdeEventQueue extends EventQueue { } else if (ke.getID() == KeyEvent.KEY_RELEASED) { switch (ke.getKeyCode()) { - case (KeyEvent.VK_CONTROL): + case KeyEvent.VK_CONTROL: ctrlIsPressedCount--; break; - case (KeyEvent.VK_ALT): + case KeyEvent.VK_ALT: if (ke.getKeyLocation() == KeyEvent.KEY_LOCATION_LEFT) { leftAltIsPressed = false; } @@ -684,8 +684,8 @@ public class IdeEventQueue extends EventQueue { } } - private MouseEvent lastClickEvent = null; - private long lastClickTime = 0L; + private MouseEvent lastClickEvent; + private long lastClickTime; private void setLastClickEvent(@Nullable MouseEvent event) { lastClickEvent = event; @@ -1151,7 +1151,7 @@ public class IdeEventQueue extends EventQueue { private final FrequentEventDetector myFrequentEventDetector = new FrequentEventDetector(1009, 100); @Override - public void postEvent(AWTEvent theEvent) { + public void postEvent(@NotNull AWTEvent theEvent) { myFrequentEventDetector.eventHappened(); super.postEvent(theEvent); } diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/updater/SendStatisticsComponent.java b/platform/platform-impl/src/com/intellij/internal/statistic/updater/SendStatisticsComponent.java index 154b3b09b17b..fdd5f1cf773b 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/updater/SendStatisticsComponent.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/updater/SendStatisticsComponent.java @@ -15,18 +15,20 @@ */ package com.intellij.internal.statistic.updater; -import com.intellij.ide.AppLifecycleListener; +import com.intellij.ide.FrameStateListener; +import com.intellij.ide.FrameStateManager; import com.intellij.internal.statistic.StatisticsUploadAssistant; import com.intellij.internal.statistic.connect.StatisticsService; import com.intellij.internal.statistic.connect.StatisticsServiceEP; import com.intellij.notification.NotificationDisplayType; import com.intellij.notification.NotificationsConfiguration; import com.intellij.notification.impl.NotificationsConfigurationImpl; -import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Ref; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.openapi.wm.ex.WindowManagerEx; +import com.intellij.openapi.wm.impl.IdeFrameImpl; import com.intellij.util.Alarm; import org.jetbrains.annotations.NotNull; @@ -40,7 +42,9 @@ public class SendStatisticsComponent implements ApplicationComponent { private final Alarm myAlarm; - public SendStatisticsComponent() { + private final FrameStateManager myFrameStateManager; + + public SendStatisticsComponent(@NotNull FrameStateManager frameStateManager) { myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, ApplicationManager.getApplication()); NotificationsConfigurationImpl.remove("SendUsagesStatistics"); @@ -48,22 +52,26 @@ public class SendStatisticsComponent implements ApplicationComponent { StatisticsNotificationManager.GROUP_DISPLAY_ID, NotificationDisplayType.STICKY_BALLOON, false); + + myFrameStateManager = frameStateManager; } private void runStatisticsService() { final StatisticsService statisticsService = StatisticsUploadAssistant.getStatisticsService(); if (StatisticsUploadAssistant.isShouldShowNotification()) { - Application app = ApplicationManager.getApplication(); - app.getMessageBus().connect(app).subscribe(AppLifecycleListener.TOPIC, new AppLifecycleListener.Adapter() { + myFrameStateManager.addListener(new FrameStateListener.Adapter() { @Override - public void appFrameCreated(String[] commandLineArgs, @NotNull Ref willOpenProject) { - myAlarm.addRequest(new Runnable() { - @Override - public void run() { - StatisticsNotificationManager.showNotification(statisticsService); - } - }, 30 * 1000); + public void onFrameActivated() { + if (((WindowManagerEx)WindowManager.getInstance()).getMostRecentFocusedWindow() instanceof IdeFrameImpl) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + StatisticsNotificationManager.showNotification(statisticsService); + } + }); + myFrameStateManager.removeListener(this); + } } }); } diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressDialog.java b/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressDialog.java index 3acd43910217..ce1264b644bc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressDialog.java @@ -58,15 +58,14 @@ class ProgressDialog implements Disposable { double fraction = myProgressWindow.getFraction(); String text2 = myProgressWindow.getText2(); - myTextLabel.setText(text != null && !text.isEmpty() ? text : " "); - if (myProgressBar.isShowing()) { final int perc = (int)(fraction * 100); myProgressBar.setIndeterminate(perc == 0 || myProgressWindow.isIndeterminate()); myProgressBar.setValue(perc); } - myText2Label.setText(getTitle2Text(text2, myText2Label.getWidth())); + myTextLabel.setText(fitTextToLabel(text, myTextLabel)); + myText2Label.setText(fitTextToLabel(text2, myText2Label)); myTitlePanel.setText(myProgressWindow.getTitle() != null && !myProgressWindow.getTitle().isEmpty() ? myProgressWindow.getTitle() : " "); @@ -77,14 +76,14 @@ class ProgressDialog implements Disposable { } }; - private String getTitle2Text(String fullText, int labelWidth) { + @NotNull + private static String fitTextToLabel(@Nullable String fullText, @NotNull JLabel label) { if (fullText == null || fullText.isEmpty()) return " "; - while (myText2Label.getFontMetrics(myText2Label.getFont()).stringWidth(fullText) > labelWidth) { + while (label.getFontMetrics(label.getFont()).stringWidth(fullText) > label.getWidth()) { int sep = fullText.indexOf(File.separatorChar, 4); if (sep < 0) return fullText; fullText = "..." + fullText.substring(sep); } - return fullText; } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingManagerImpl.java index 7c702ec93313..78b297d68e57 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingManagerImpl.java @@ -205,6 +205,7 @@ public class EncodingManagerImpl extends EncodingManager implements PersistentSt for (Project project : projects) { result.addAll(EncodingProjectManager.getInstance(project).getFavorites()); } + result.addAll(EncodingProjectManagerImpl.widelyKnownCharsets()); return result; } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingProjectManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingProjectManagerImpl.java index 6135881f6d29..116069d219d7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingProjectManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingProjectManagerImpl.java @@ -85,7 +85,6 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager implement }); } - //null key means project private final Map myMapping = ContainerUtil.newConcurrentMap(); private volatile Charset myProjectCharset; @@ -96,7 +95,7 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager implement List files = new ArrayList(myMapping.keySet()); ContainerUtil.quickSort(files, new Comparator() { @Override - public int compare(final VirtualFile o1, final VirtualFile o2) { + public int compare(@NotNull final VirtualFile o1, @NotNull final VirtualFile o2) { return o1.getPath().compareTo(o2.getPath()); } }); @@ -235,9 +234,15 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager implement @Override @NotNull public Collection getFavorites() { - Set result = new HashSet(); + Set result = widelyKnownCharsets(); result.addAll(myMapping.values()); result.add(getDefaultCharset()); + return result; + } + + @NotNull + static Set widelyKnownCharsets() { + Set result = new HashSet(); result.add(CharsetToolkit.UTF8_CHARSET); result.add(CharsetToolkit.getDefaultSystemCharset()); result.add(CharsetToolkit.UTF_16_CHARSET); @@ -245,7 +250,6 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager implement result.add(CharsetToolkit.forName("US-ASCII")); result.add(EncodingManager.getInstance().getDefaultCharset()); result.add(EncodingManager.getInstance().getDefaultCharsetForPropertiesFiles(null)); - result.remove(null); return result; } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java index 4685cabd0054..b45c38c28e06 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsData.java @@ -17,6 +17,7 @@ package com.intellij.openapi.vfs.newvfs.impl; import com.intellij.openapi.application.ApplicationAdapter; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.vfs.InvalidVirtualFileAccessException; import com.intellij.openapi.vfs.newvfs.persistent.FSRecords; import com.intellij.util.ArrayUtil; @@ -73,6 +74,7 @@ import static com.intellij.util.ObjectUtils.assertNotNull; * @author peter */ public class VfsData { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.newvfs.impl.VfsData"); private static final int SEGMENT_BITS = 9; private static final int SEGMENT_SIZE = 1 << SEGMENT_BITS; private static final int OFFSET_MASK = SEGMENT_SIZE - 1; @@ -223,6 +225,9 @@ public class VfsData { } void setFlag(int id, int mask, boolean value) { + if (LOG.isDebugEnabled()) { + LOG.debug("Set flag " + Integer.toHexString(mask) + "=" + value + " for id=" + id); + } assert (mask & ~ALL_FLAGS_MASK) == 0 : "Unexpected flag"; int offset = getOffset(id) * 2 + 1; while (true) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java index d47bdd808339..16ed50c905d2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java @@ -1061,7 +1061,7 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone else if (VirtualFile.PROP_WRITABLE.equals(propertyChangeEvent.getPropertyName())) { executeSetWritable(file, ((Boolean)newValue).booleanValue()); if (LOG.isDebugEnabled()) { - LOG.debug("File " + file + " writable=" + file.isWritable()); + LOG.debug("File " + file + " writable=" + file.isWritable() + " id=" + getFileId(file)); } } else if (VirtualFile.PROP_HIDDEN.equals(propertyChangeEvent.getPropertyName())) { diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteSdkFactory.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkFactory.java index dc28679937fe..cf3c5bbcace5 100644 --- a/platform/platform-impl/src/com/intellij/remote/RemoteSdkFactory.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkFactory.java @@ -30,6 +30,8 @@ public interface RemoteSdkFactory { Sdk createRemoteSdk(@Nullable Project project, @NotNull T data, @Nullable String sdkName, Collection existingSdks) throws RemoteSdkException; + String generateSdkHomePath(@NotNull T data); + Sdk createUnfinished(T data, Collection existingSdks); String getDefaultUnfinishedName(); diff --git a/platform/platform-resources/src/brokenPlugins.txt b/platform/platform-resources/src/brokenPlugins.txt index 2a541bdc52f2..022c92e9e5eb 100644 --- a/platform/platform-resources/src/brokenPlugins.txt +++ b/platform/platform-resources/src/brokenPlugins.txt @@ -1,7 +1,7 @@ // This file contains list of broken plugins. // Each line contains plugin ID and list of versions that are broken. // If plugin name or version contains a space you can quote it like in command line. -NodeJS 142.3224 142.2650 142.2492 142.2481 142.2064 141.1108 140.2045 140.1669 140.642 139.173 139.105 139.496 139.1 139.8 138.2196 138.2254 138.1684 138.1744 138.1879 138.2051 138.1367 138.1495 138.1189 138.1145 138.937 138.1013 138.921 138.447 138.172 138.317 138.21 138.35 138.96 138.85 136.1205 134.1276 134.1163 134.1145 134.1081 134.1039 134.985 134.680 134.31 134.307 134.262 134.198 134.125 136.1141 +NodeJS 142.4100 142.3224 142.2650 142.2492 142.2481 142.2064 141.1108 140.2045 140.1669 140.642 139.173 139.105 139.496 139.1 139.8 138.2196 138.2254 138.1684 138.1744 138.1879 138.2051 138.1367 138.1495 138.1189 138.1145 138.937 138.1013 138.921 138.447 138.172 138.317 138.21 138.35 138.96 138.85 136.1205 134.1276 134.1163 134.1145 134.1081 134.1039 134.985 134.680 134.31 134.307 134.262 134.198 134.125 136.1141 com.jetbrains.php 140.2765 141.332 139.732 139.659 139.496 139.173 139.105 138.2502 138.2000.2262 138.1751 138.1806 138.1505 138.1161 138.826 136.1768 136.1672 134.1456 133.982 133.679 133.51 133.326 131.98 131.374 131.332 131.235 131.205 130.1639 130.1481 130.1176 129.91 129.814 129.672 129.362 127.67 127.100 126.334 123.66 122.875 121.62 121.390 121.215 121.12 com.jetbrains.lang.ejs 131.17 131.12 com.jetbrains.twig 133.51 130.1639 diff --git a/platform/platform-tests/testSrc/com/intellij/concurrency/JobUtilTest.java b/platform/platform-tests/testSrc/com/intellij/concurrency/JobUtilTest.java index 0bfdbb0dc6c6..9864dc24b7e5 100644 --- a/platform/platform-tests/testSrc/com/intellij/concurrency/JobUtilTest.java +++ b/platform/platform-tests/testSrc/com/intellij/concurrency/JobUtilTest.java @@ -390,7 +390,7 @@ public class JobUtilTest extends PlatformTestCase { } } - public void testTasksIsDoneAfterCancelInTheMiddleOfTheExecutionReturnsFalseUntilFinished() throws ExecutionException, InterruptedException { + public void testAfterCancelInTheMiddleOfTheExecutionTaskIsDoneReturnsFalseUntilFinished() throws ExecutionException, InterruptedException { Random random = new Random(); for (int i=0; i<100; i++) { final AtomicBoolean finished = new AtomicBoolean(); @@ -407,7 +407,7 @@ public class JobUtilTest extends PlatformTestCase { TimeoutUtil.sleep(random.nextInt(100)); job.cancel(); long start = System.currentTimeMillis(); - while (!finished.get() && (started.get() || System.currentTimeMillis() < start + 2000)) { + while (!job.isDone() && (started.get() || System.currentTimeMillis() < start + 2000)) { boolean wasDone = job.isDone(); boolean wasStarted = started.get(); boolean wasFinished = finished.get(); @@ -415,6 +415,10 @@ public class JobUtilTest extends PlatformTestCase { assertTrue(wasStarted+", "+wasDone, wasDone == !wasStarted); } // else no guarantees + + if (wasDone) { + assertTrue(wasFinished); + } } } } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CompletionAutoPopupTester.groovy b/platform/testFramework/src/com/intellij/testFramework/fixtures/CompletionAutoPopupTester.groovy index 4f01645b19c3..2bc253654602 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CompletionAutoPopupTester.groovy +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CompletionAutoPopupTester.groovy @@ -14,7 +14,6 @@ * limitations under the License. */ package com.intellij.testFramework.fixtures - import com.intellij.codeInsight.completion.CompletionPhase import com.intellij.codeInsight.completion.impl.CompletionServiceImpl import com.intellij.codeInsight.editorActions.CompletionAutoPopupHandler @@ -22,6 +21,8 @@ import com.intellij.codeInsight.lookup.LookupManager import com.intellij.codeInsight.lookup.impl.LookupImpl import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.ex.DocumentEx +import com.intellij.openapi.util.SystemInfo +import com.intellij.openapi.util.io.FileUtil import com.intellij.psi.PsiDocumentManager import com.intellij.testFramework.UsefulTestCase import com.intellij.util.ui.UIUtil @@ -54,7 +55,7 @@ class CompletionAutoPopupTester { waitPhase { !(it instanceof CompletionPhase.CommittingDocuments || it instanceof CompletionPhase.Synchronous || it instanceof CompletionPhase.BgCalculation) } } - private void waitPhase(Closure condition) { + private static void waitPhase(Closure condition) { for (j in 1..1000) { def phase = null UsefulTestCase.edt { phase = CompletionServiceImpl.completionPhase } @@ -65,6 +66,16 @@ class CompletionAutoPopupTester { println "Free memory: " + Runtime.runtime.freeMemory() + " of " + Runtime.runtime.totalMemory() + "\n" UsefulTestCase.printThreadDump() println "\n\n----------------------------\n\n" + if (SystemInfo.isLinux) { + try { + Process process = new ProcessBuilder().command(["top", "-b", "-n", "1"] as String[]).redirectErrorStream(true).start(); + println FileUtil.loadTextAndClose(process.getInputStream()) + } + catch (IOException e) { + e.printStackTrace() + } + } + println "\n\n----------------------------\n\n" } Thread.sleep(10) } diff --git a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java index 4851697406ce..1ff61cbf224d 100644 --- a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java +++ b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java @@ -78,7 +78,6 @@ public class GitCherryPicker extends VcsCherryPicker { private static final String CHERRY_PICK_HEAD_FILE = "CHERRY_PICK_HEAD"; private static final Logger LOG = Logger.getInstance(GitCherryPicker.class); - private static final String NAME = "Cherry-Pick"; @NotNull private final Project myProject; @NotNull private final Git myGit; @@ -521,7 +520,7 @@ public class GitCherryPicker extends VcsCherryPicker { @NotNull @Override public String getActionTitle() { - return isAutoCommit() ? NAME : NAME + "..."; + return "Cherry-Pick"; } private boolean isAutoCommit() { diff --git a/plugins/git4idea/src/git4idea/commands/GitImpl.java b/plugins/git4idea/src/git4idea/commands/GitImpl.java index db3f45b77aa9..3b1d1bbc6ebd 100644 --- a/plugins/git4idea/src/git4idea/commands/GitImpl.java +++ b/plugins/git4idea/src/git4idea/commands/GitImpl.java @@ -18,6 +18,7 @@ package git4idea.commands; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; @@ -149,6 +150,7 @@ public class GitImpl implements Git { handler.setUrl(url); handler.addParameters("--progress"); handler.addParameters(url); + handler.endOptions(); handler.addParameters(clonedDirectoryName); addListeners(handler, listeners); return handler; @@ -604,7 +606,7 @@ public class GitImpl implements Git { GitLineHandler handler = handlerConstructor.compute(); handler.addLineListener(new GitLineHandlerListener() { @Override public void onLineAvailable(String line, Key outputType) { - if (isError(line)) { + if (looksLikeError(line)) { errorOutput.add(line); } else { output.add(line); @@ -624,7 +626,7 @@ public class GitImpl implements Git { handler.runInCurrentThread(null); authFailed = handler.hasHttpAuthFailed(); - success = !startFailed.get() && errorOutput.isEmpty() && (handler.isIgnoredErrorCode(exitCode.get()) || exitCode.get() == 0); + success = !startFailed.get() && (handler.isIgnoredErrorCode(exitCode.get()) || exitCode.get() == 0); } while (authFailed && authAttempt++ < 2); return new GitCommandResult(success, exitCode.get(), errorOutput, output, null); @@ -668,21 +670,18 @@ public class GitImpl implements Git { return ObjectUtils.assertNotNull(compoundResult); } - /** - * Check if the line looks line an error message - */ - private static boolean isError(String text) { - for (String indicator : ERROR_INDICATORS) { - if (text.trim().toLowerCase().startsWith(indicator.toLowerCase())) { - return true; + private static boolean looksLikeError(@NotNull final String text) { + return ContainerUtil.exists(ERROR_INDICATORS, new Condition() { + @Override + public boolean value(@NotNull String indicator) { + return StringUtil.startsWithIgnoreCase(text.trim(), indicator); } - } - return false; + }); } // could be upper-cased, so should check case-insensitively public static final String[] ERROR_INDICATORS = { - "error", "remote: error", "fatal", + "error:", "remote: error", "fatal:", "Cannot", "Could not", "Interactive rebase already started", "refusing to pull", "cannot rebase:", "conflict", "unable" }; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java index 4aa907e1b156..f0b4263e1fc6 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java @@ -322,31 +322,16 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl 0 || file instanceof GroovyFile && ((GroovyFile)file).getPackageName().isEmpty()) { - PsiClass aClass = facade.findClass(qName, ref.getResolveScope()); - if (aClass != null) { - boolean isAccessible = PsiUtil.isAccessible(ref, aClass); - return new GroovyResolveResult[]{new GroovyResolveResultImpl(aClass, isAccessible)}; - } - } - } - - if (kind == ReferenceKind.CLASS_OR_PACKAGE_FQ || kind == ReferenceKind.PACKAGE_FQ) { - PsiPackage aPackage = facade.findPackage(qName); - if (aPackage != null) { - return new GroovyResolveResult[]{new GroovyResolveResultImpl(aPackage, true)}; - } + PsiElement element = resolveClassOrPackagePreferInner(ref, kind, qName, JavaPsiFacade.getInstance(manager.getProject())); + if (element != null) { + boolean accessible = !(element instanceof PsiClass) || PsiUtil.isAccessible(ref, (PsiClass)element); + return new GroovyResolveResult[]{new GroovyResolveResultImpl(element, accessible)}; } break; case CLASS: { - EnumSet kinds = kind == ReferenceKind.CLASS - ? ClassHint.RESOLVE_KINDS_CLASS : ClassHint.RESOLVE_KINDS_CLASS_PACKAGE; + EnumSet kinds = ClassHint.RESOLVE_KINDS_CLASS; ResolverProcessor processor = new ClassResolverProcessor(refName, ref, kinds); GrCodeReferenceElement qualifier = ref.getQualifier(); if (qualifier != null) { @@ -365,13 +350,6 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl 0) return candidates; } - - if (kind == ReferenceKind.CLASS_OR_PACKAGE) { - PsiPackage pkg = JavaPsiFacade.getInstance(ref.getProject()).findPackage(refName); - if (pkg != null) { - return new GroovyResolveResult[]{new GroovyResolveResultImpl(pkg, true)}; - } - } } break; @@ -444,6 +422,36 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl 0; + if (qualified || file instanceof GroovyFile && ((GroovyFile)file).getPackageName().isEmpty()) { + //prefer inner classes, because groovyc does that as well + PsiElement container = qualified ? resolveClassOrPackagePreferInner(ref, kind, StringUtil.getPackageName(qName), facade) : null; + PsiClass aClass = container instanceof PsiClass && PsiUtil.isAccessible(ref, (PsiClass)container) + ? ((PsiClass)container).findInnerClassByName(StringUtil.getShortName(qName), true) + : null; + if (aClass == null) { + aClass = facade.findClass(qName, ref.getResolveScope()); + } + if (aClass != null) { + return aClass; + } + } + } + + if (kind == ReferenceKind.CLASS_OR_PACKAGE_FQ || kind == ReferenceKind.PACKAGE_FQ) { + return facade.findPackage(qName); + } + + return null; + } + private static PsiFile getContainingFileSkippingStubFiles(GrCodeReferenceElementImpl ref) { PsiFile file = ref.getContainingFile(); while (file != null && !file.isPhysical() && file.getContext() != null) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrTraitUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrTraitUtil.java index 8af949509fd6..0b2ec89273ec 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrTraitUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrTraitUtil.java @@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.util; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.impl.compiled.ClsClassImpl; import com.intellij.util.Function; @@ -36,6 +37,12 @@ import static com.intellij.psi.PsiModifier.ABSTRACT; */ public class GrTraitUtil { private static final Logger LOG = Logger.getInstance(GrTraitUtil.class); + private static final PsiTypeMapper ID_MAPPER = new PsiTypeMapper() { + @Override + public PsiType visitClassType(PsiClassType classType) { + return classType; + } + }; @Contract("null -> false") public static boolean isInterface(@Nullable PsiClass aClass) { @@ -73,7 +80,7 @@ public class GrTraitUtil { && AnnotationUtil.isAnnotated(containingClass, "groovy.transform.Trait", false); } - public static PsiMethod createTraitMethodFromCompiledHelperMethod(final PsiMethod compiledMethod, PsiClass trait) { + public static PsiMethod createTraitMethodFromCompiledHelperMethod(final PsiMethod compiledMethod, final PsiClass trait) { assert compiledMethod.getParameterList().getParametersCount() > 0; final GrLightMethodBuilder result = new GrLightMethodBuilder(compiledMethod.getManager(), compiledMethod.getName()); @@ -84,59 +91,68 @@ public class GrTraitUtil { result.getTypeParameterList().addParameter(parameter); } - final Map substitutionMap = ContainerUtil.newTroveMap(); - for (PsiTypeParameter parameter : trait.getTypeParameters()) { - substitutionMap.put(parameter.getName(), parameter); - } + final PsiTypeVisitor corrector = createCorrector(compiledMethod, trait); - final PsiElementFactory myElementFactory = JavaPsiFacade.getInstance(compiledMethod.getProject()).getElementFactory(); - final PsiTypeVisitor corrector = new PsiTypeMapper() { - - @Nullable - @Override - public PsiType visitClassType(PsiClassType classType) { - final PsiClass resolved = classType.resolve(); - // if resolved to method parameter -> return as is - if (resolved instanceof PsiTypeParameter && compiledMethod.equals(((PsiTypeParameter)resolved).getOwner())) return classType; - if (resolved == null) { - // if not resolved -> try to get from map - final PsiTypeParameter byName = substitutionMap.get(classType.getCanonicalText()); - return byName == null ? classType : myElementFactory.createType(byName); - } - else { - // if resolved -> get from map anyways - final PsiTypeParameter byName = substitutionMap.get(resolved.getName()); - final PsiTypeVisitor $this = this; - final PsiType[] substitutes = !classType.hasParameters() ? PsiType.EMPTY_ARRAY : ContainerUtil.map2Array( - classType.getParameters(), PsiType.class, new Function() { - @Override - public PsiType fun(PsiType type) { - return type.accept($this); - } - } - ); - return myElementFactory.createType(byName != null ? byName : resolved, substitutes); - } - } - }; - - for (int i = 1; i < compiledMethod.getParameterList().getParameters().length; i++) { - final PsiParameter originalParameter = compiledMethod.getParameterList().getParameters()[i]; - final PsiType originalType = originalParameter.getType(); - final PsiType correctedType = trait.hasTypeParameters() ? originalType.accept(corrector) : originalType; + final PsiParameter[] methodParameters = compiledMethod.getParameterList().getParameters(); + for (int i = 1; i < methodParameters.length; i++) { + final PsiParameter originalParameter = methodParameters[i]; + final PsiType correctedType = originalParameter.getType().accept(corrector); result.addParameter(originalParameter.getName(), correctedType, false); } for (PsiClassType type : compiledMethod.getThrowsList().getReferencedTypes()) { - final PsiType correctedType = trait.hasTypeParameters() ? type.accept(corrector) : type; + final PsiType correctedType = type.accept(corrector); result.getThrowsList().addReference(correctedType instanceof PsiClassType ? (PsiClassType)correctedType : type); } { final PsiType originalType = compiledMethod.getReturnType(); - result.setReturnType(originalType != null && trait.hasTypeParameters() ? originalType.accept(corrector) : originalType); + result.setReturnType(originalType == null ? null : originalType.accept(corrector)); } return result; } + + @NotNull + private static PsiTypeMapper createCorrector(final PsiMethod compiledMethod, final PsiClass trait) { + final PsiTypeParameter[] traitTypeParameters = trait.getTypeParameters(); + if (traitTypeParameters.length == 0) return ID_MAPPER; + + final Map substitutionMap = ContainerUtil.newTroveMap(); + for (PsiTypeParameter parameter : traitTypeParameters) { + substitutionMap.put(parameter.getName(), parameter); + } + + final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(trait.getProject()).getElementFactory(); + return new PsiTypeMapper() { + + @Nullable + @Override + public PsiType visitClassType(PsiClassType originalType) { + final PsiClass resolved = originalType.resolve(); + // if resolved to method parameter -> return as is + if (resolved instanceof PsiTypeParameter && compiledMethod.equals(((PsiTypeParameter)resolved).getOwner())) return originalType; + final PsiType[] typeParameters = originalType.getParameters(); + final PsiTypeParameter byName = substitutionMap.get(originalType.getCanonicalText()); + if (byName != null) { + assert typeParameters.length == 0; + return elementFactory.createType(byName); + } + if (resolved == null) return originalType; + if (typeParameters.length == 0) return originalType; // do not go deeper + + final Ref hasChanges = Ref.create(false); + final PsiTypeVisitor $this = this; + final PsiType[] substitutes = ContainerUtil.map2Array(typeParameters, PsiType.class, new Function() { + @Override + public PsiType fun(PsiType type) { + final PsiType mapped = type.accept($this); + hasChanges.set(mapped != type); + return mapped; + } + }); + return hasChanges.get() ? elementFactory.createType(resolved, substitutes) : originalType; + } + }; + } } diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java index cf368111a7be..53fc193eec10 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java @@ -290,7 +290,7 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable { PySdkService.getInstance().solidifySdk(item); } myProjectSdksModel.apply(); - newSdk = newSdk == null ? null : myProjectSdksModel.findSdk(newSdk.getName()); + newSdk = newSdk == null ? null : myProjectSdksModel.findSdk(newSdk); mySdkCombo.getModel().setSelectedItem(newSdk); final Sdk prevSdk = getSdk(); diff --git a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java index f9edc9781eee..2c1944e3b8da 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java +++ b/python/ide/src/com/jetbrains/python/configuration/PythonSdkDetailsDialog.java @@ -406,7 +406,7 @@ public class PythonSdkDetailsDialog extends DialogWrapper { } private void reloadSdk(Sdk currentSdk) { - PythonSdkType.setupSdkPaths(myProject, null, currentSdk, myModificators.get(currentSdk)); // or must it be a RunWriteAction? + PythonSdkType.setupSdkPaths(currentSdk, myProject, null, myModificators.get(currentSdk)); // or must it be a RunWriteAction? } private class ToggleVirtualEnvFilterButton extends ToggleActionButton implements DumbAware { diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java index b576a41a27c4..1cf312001df2 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java @@ -20,7 +20,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.StandardFileSystems; @@ -39,6 +38,7 @@ import com.jetbrains.python.psi.resolve.*; import com.jetbrains.python.psi.types.PyClassLikeType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; +import com.jetbrains.python.sdk.PySdkUpdater; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -137,10 +137,10 @@ public class PyUserSkeletonsUtil { return null; } - public static void addUserSkeletonsRoot(@NotNull SdkModificator sdkModificator) { + public static void addUserSkeletonsRoot(@NotNull PySdkUpdater sdkUpdater) { final VirtualFile root = getUserSkeletonsDirectory(); if (root != null) { - sdkModificator.addRoot(root, OrderRootType.CLASSES); + sdkUpdater.addRoot(root, OrderRootType.CLASSES); } } diff --git a/python/src/com/jetbrains/python/sdk/PySdkUpdater.java b/python/src/com/jetbrains/python/sdk/PySdkUpdater.java new file mode 100644 index 000000000000..ae0985d973b0 --- /dev/null +++ b/python/src/com/jetbrains/python/sdk/PySdkUpdater.java @@ -0,0 +1,146 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.sdk; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkModificator; +import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * This sdk updater class is a facade to Sdk to make changes in it in a reliable way. + * Working with sdk instance instead of this class can be wrong, because an instance can become + * obsolete being substituted in sdk table by a new one. Or already created sdk modificator can be committed, + * discarding the changes that we doing with the sdk. + * + * + * There are two ways of creation of the facade: + * 1) by sdk path - in this case we'll get the current actual sdk instance + * from sdk table by that path, creating and committing SdkModificator on every change + * 2) by sdkModificator - in that case we'll make changes to that modificator, but it is not committed, + * because it has been created outside of the updater. + * + * + * @author traff + */ +public abstract class PySdkUpdater { + @NotNull + public abstract Sdk getSdk(); + + public abstract void modifySdk(@NotNull SdkModificationProcessor processor); + + public void addRoot(@NotNull final VirtualFile root, @NotNull final OrderRootType rootType) { + modifySdk(new SdkModificationProcessor() { + @Override + public void process(@NotNull Sdk sdk, @NotNull SdkModificator sdkModificator) { + sdkModificator.addRoot(root, rootType); + } + }); + } + + public void removeRoots(@NotNull final OrderRootType rootType) { + modifySdk(new PySdkUpdater.SdkModificationProcessor() { + @Override + public void process(@NotNull Sdk sdk, @NotNull SdkModificator sdkModificator) { + sdkModificator.removeRoots(rootType); + } + }); + } + + public static PySdkUpdater fromSdkPath(@Nullable String sdkPath) { + return new JdkTableUpdater(sdkPath); + } + + public static PySdkUpdater fromSdkModificator(@NotNull Sdk sdk, @NotNull SdkModificator sdkModificator) { + return new SdkModificatorUpdater(sdk, sdkModificator); + } + + @Nullable + public abstract String getHomePath(); + + private static class JdkTableUpdater extends PySdkUpdater { + private final String mySdkPath; + + private JdkTableUpdater(@Nullable String path) { + mySdkPath = path; + } + + @NotNull + @Override + public Sdk getSdk() { + Sdk sdk = PythonSdkType.findSdkByPath(mySdkPath); + if (sdk != null) { + return sdk; + } + else { + return new ProjectJdkImpl(getHomePath(), PythonSdkType.getInstance()); + } + } + + @Nullable + @Override + public String getHomePath() { + return mySdkPath; + } + + public void modifySdk(@NotNull SdkModificationProcessor processor) { + ApplicationManager.getApplication().assertIsDispatchThread(); + + Sdk sdk = PythonSdkType.findSdkByPath(mySdkPath); + + if (sdk != null) { + SdkModificator modificator = getSdk().getSdkModificator(); + processor.process(sdk, modificator); + modificator.commitChanges(); + } + } + } + + private static class SdkModificatorUpdater extends PySdkUpdater { + private SdkModificator myModificator; + private Sdk mySdk; + + public SdkModificatorUpdater(@NotNull Sdk sdk, @NotNull SdkModificator modificator) { + mySdk = sdk; + myModificator = modificator; + } + + @NotNull + @Override + public Sdk getSdk() { + return mySdk; + } + + @NotNull + @Override + public String getHomePath() { + return mySdk.getHomePath(); + } + + public void modifySdk(@NotNull SdkModificationProcessor processor) { + processor.process(getSdk(), myModificator); + } + } + + + public interface SdkModificationProcessor { + void process(@NotNull Sdk sdk, @NotNull SdkModificator sdkModificator); + } +} diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java index bd1d0ad4ec24..77a9f0e2ae25 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java @@ -30,6 +30,7 @@ import com.intellij.notification.Notifications; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileChooser.FileChooserDescriptor; @@ -45,10 +46,7 @@ import com.intellij.openapi.projectRoots.*; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileSystemUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.CharFilter; @@ -63,6 +61,7 @@ import com.intellij.remote.*; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import com.intellij.util.NullableConsumer; +import com.intellij.util.ui.UIUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; import com.jetbrains.python.PythonFileType; @@ -242,7 +241,7 @@ public class PythonSdkType extends SdkType { public static boolean isVagrant(@Nullable Sdk sdk) { if (sdk != null && sdk.getSdkAdditionalData() instanceof PyRemoteSdkAdditionalDataBase) { - PyRemoteSdkAdditionalDataBase data = (PyRemoteSdkAdditionalDataBase) sdk.getSdkAdditionalData(); + PyRemoteSdkAdditionalDataBase data = (PyRemoteSdkAdditionalDataBase)sdk.getSdkAdditionalData(); return data.getRemoteConnectionType() == CredentialsType.VAGRANT; } @@ -519,45 +518,63 @@ public class PythonSdkType extends SdkType { return true; // run setupSdkPaths only once (from PythonSdkDetailsStep). Skip this from showCustomCreateUI } - public static void setupSdkPaths(Sdk sdk, @Nullable Project project, @Nullable Component ownerComponent) { - final SdkModificator sdkModificator = sdk.getSdkModificator(); - final boolean success = setupSdkPaths(project, ownerComponent, sdk, sdkModificator); - if (success) { - sdkModificator.commitChanges(); - } - else { - Messages.showErrorDialog( - project, - PyBundle.message("MSG.cant.setup.sdk.$0", FileUtil.toSystemDependentName(sdk.getSdkModificator().getHomePath())), - PyBundle.message("MSG.title.bad.sdk") - ); - } + public static void setupSdkPaths(@NotNull final Sdk sdk, + @Nullable final Project project, + @Nullable final Component ownerComponent, + @NotNull final SdkModificator sdkModificator) { + doSetupSdkPaths(project, ownerComponent, PySdkUpdater.fromSdkModificator(sdk, sdkModificator)); } - public static boolean setupSdkPaths(@Nullable final Project project, - @Nullable final Component ownerComponent, - @NotNull final Sdk sdk, - @NotNull final SdkModificator sdkModificator) { - if (isRemote(sdk) && project == null && ownerComponent == null) { + + public static void setupSdkPaths(final Sdk sdk, @Nullable final Project project, @Nullable final Component ownerComponent) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + final boolean success = doSetupSdkPaths(project, ownerComponent, PySdkUpdater.fromSdkPath(sdk.getHomePath())); + + if (!success) { + Messages.showErrorDialog( + project, + PyBundle.message("MSG.cant.setup.sdk.$0", FileUtil.toSystemDependentName(sdk.getSdkModificator().getHomePath())), + PyBundle.message("MSG.title.bad.sdk") + ); + } + } + }, ModalityState.NON_MODAL); + } + + private static boolean doSetupSdkPaths(@Nullable final Project project, + @Nullable final Component ownerComponent, + @NotNull final PySdkUpdater sdkUpdater) { + if (isRemote(sdkUpdater.getSdk()) && project == null && ownerComponent == null) { LOG.error("For refreshing skeletons of remote SDK, either project or owner component must be specified"); } final ProgressManager progressManager = ProgressManager.getInstance(); - final Ref sdkPathsUpdatedRef = new Ref(false); - final Task.Modal setupTask = new Task.Modal(project, "Setting up library files for " + sdk.getName(), false) { - public void run(@NotNull final ProgressIndicator indicator) { - sdkModificator.removeAllRoots(); - try { - updateSdkRootsFromSysPath(sdk, sdkModificator, indicator); - updateUserAddedPaths(sdk, sdkModificator, indicator); - PythonSdkUpdater.getInstance().markAlreadyUpdated(sdk.getHomePath()); - sdkPathsUpdatedRef.set(true); - } - catch (InvalidSdkException ignored) { + boolean sdkPathsUpdated = UIUtil.invokeAndWaitIfNeeded( + new Computable() { + @Override + public Boolean compute() { + sdkUpdater.modifySdk(new PySdkUpdater.SdkModificationProcessor() { + @Override + public void process(@NotNull Sdk sdk, + @NotNull SdkModificator sdkModificator) { + sdkModificator.removeAllRoots(); + } + }); + try { + updateSdkRootsFromSysPath(sdkUpdater); + updateUserAddedPaths(sdkUpdater); + PythonSdkUpdater.getInstance() + .markAlreadyUpdated(sdkUpdater.getHomePath()); + return true; + } + catch (InvalidSdkException ignored) { + } + return false; } } - }; - progressManager.run(setupTask); - final Boolean sdkPathsUpdated = sdkPathsUpdatedRef.get(); + ); + final Application application = ApplicationManager.getApplication(); if (sdkPathsUpdated && !application.isUnitTestMode()) { application.invokeLater(new Runnable() { @@ -567,20 +584,20 @@ public class PythonSdkType extends SdkType { @Override public void run(@NotNull ProgressIndicator indicator) { try { - final String skeletonsPath = getSkeletonsPath(PathManager.getSystemPath(), sdk.getHomePath()); - PythonSdkUpdater.updateSdk(project, ownerComponent, sdk, skeletonsPath); + final String skeletonsPath = getSkeletonsPath(PathManager.getSystemPath(), sdkUpdater.getHomePath()); + PythonSdkUpdater.updateSdk(project, ownerComponent, sdkUpdater, skeletonsPath); } catch (InvalidSdkException e) { // If the SDK is invalid, the user should worry about the SDK itself, not about skeletons generation errors - if (isVagrant(sdk)) { + if (isVagrant(sdkUpdater.getSdk())) { notifyRemoteSdkSkeletonsFail(e, new Runnable() { @Override public void run() { - setupSdkPaths(project, ownerComponent, sdk, sdkModificator); + setupSdkPaths(sdkUpdater.getSdk(), project, ownerComponent); } }); } - else if (!isInvalid(sdk)) { + else if (!isInvalid(sdkUpdater.getSdk())) { LOG.error(e); } } @@ -622,7 +639,8 @@ public class PythonSdkType extends SdkType { Notifications.Bus.notify( new Notification( - SKELETONS_TOPIC, "Couldn't refresh skeletons for remote interpreter", e.getMessage() + "\nLaunch vagrant and refresh skeletons", + SKELETONS_TOPIC, "Couldn't refresh skeletons for remote interpreter", + e.getMessage() + "\nLaunch vagrant and refresh skeletons", NotificationType.WARNING, notificationListener ) @@ -636,35 +654,28 @@ public class PythonSdkType extends SdkType { private final static Pattern PYTHON_NN_RE = Pattern.compile("python\\d\\.\\d.*"); - public static void updateSdkRootsFromSysPath(Sdk sdk, SdkModificator sdkModificator, ProgressIndicator indicator) + public static void updateSdkRootsFromSysPath(PySdkUpdater sdkUpdater) throws InvalidSdkException { Application application = ApplicationManager.getApplication(); boolean not_in_unit_test_mode = (application != null && !application.isUnitTestMode()); - String sdkHome = sdkModificator.getHomePath(); + String sdkHome = sdkUpdater.getHomePath(); assert sdkHome != null; final String sep = File.separator; - // we have a number of lib dirs, those listed in python's sys.path - if (indicator != null) { - indicator.setText("Adding library roots"); - } // Add folders from sys.path - if (!PySdkUtil.isRemote(sdk)) { //no sense to add roots of remote sdk + if (!PySdkUtil.isRemote(sdkUpdater.getSdk())) { //no sense to add roots of remote sdk final List paths = getSysPath(sdkHome); if (paths.size() > 0) { // add every path as root. for (String path : paths) { if (!path.contains(sep)) continue; // TODO: interpret possible 'special' paths reasonably - if (indicator != null) { - indicator.setText2(path); - } - addSdkRoot(sdkModificator, path); + addSdkRoot(sdkUpdater, path); } } } - PyUserSkeletonsUtil.addUserSkeletonsRoot(sdkModificator); - addSkeletonsRoot(sdkModificator, sdkHome); + PyUserSkeletonsUtil.addUserSkeletonsRoot(sdkUpdater); + addSkeletonsRoot(sdkUpdater, sdkHome); if (not_in_unit_test_mode) { File venv_root = getVirtualEnvRoot(sdkHome); @@ -680,57 +691,54 @@ public class PythonSdkType extends SdkType { } } } - addHardcodedPaths(sdkModificator); + addHardcodedPaths(sdkUpdater); } } - public static void updateUserAddedPaths(Sdk sdk, SdkModificator sdkModificator, ProgressIndicator indicator) + public static void updateUserAddedPaths(PySdkUpdater sdkUpdater) throws InvalidSdkException { - if (indicator != null) { - indicator.setText("Adding user-added roots"); - } - SdkAdditionalData data = sdk.getSdkAdditionalData(); + SdkAdditionalData data = sdkUpdater.getSdk().getSdkAdditionalData(); if (data instanceof PythonSdkAdditionalData) { for (VirtualFile file : ((PythonSdkAdditionalData)data).getAddedPathFiles()) { - addSdkRoot(sdkModificator, file); + addSdkRoot(sdkUpdater, file); } } } - private static void addSkeletonsRoot(@NotNull SdkModificator sdkModificator, String sdkHome) { + private static void addSkeletonsRoot(@NotNull PySdkUpdater sdkUpdater, String sdkHome) { @NonNls final String skeletonsPath = getSkeletonsPath(PathManager.getSystemPath(), sdkHome); new File(skeletonsPath).mkdirs(); final VirtualFile builtins_root = LocalFileSystem.getInstance().refreshAndFindFileByPath(skeletonsPath); assert builtins_root != null : "Cannot find skeletons path " + skeletonsPath + " in VFS"; - sdkModificator.addRoot(builtins_root, BUILTIN_ROOT_TYPE); + sdkUpdater.addRoot(builtins_root, BUILTIN_ROOT_TYPE); } - protected static void addHardcodedPaths(SdkModificator sdkModificator) { + protected static void addHardcodedPaths(PySdkUpdater sdkUpdater) { // Add python-django installed as package in Linux // NOTE: fragile and arbitrary if (SystemInfo.isLinux) { final VirtualFile file = LocalFileSystem.getInstance().findFileByPath("/usr/lib/python-django"); if (file != null) { - sdkModificator.addRoot(file, OrderRootType.CLASSES); + sdkUpdater.addRoot(file, OrderRootType.CLASSES); } } } - public static void addSdkRoot(SdkModificator sdkModificator, String path) { + public static void addSdkRoot(PySdkUpdater sdkUpdater, String path) { final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path); if (file != null) { - addSdkRoot(sdkModificator, file); + addSdkRoot(sdkUpdater, file); } else { LOG.info("Bogus sys.path entry " + path); } } - private static void addSdkRoot(@NotNull SdkModificator sdkModificator, @NotNull VirtualFile child) { + private static void addSdkRoot(@NotNull PySdkUpdater sdkUpdater, final @NotNull VirtualFile child) { // NOTE: Files marked as library sources are not considered part of project source. Since the directory of the project the // user is working on is included in PYTHONPATH with many configurations (e.g. virtualenv), we must not mark SDK paths as // library sources, only as classes. - sdkModificator.addRoot(getSdkRootVirtualFile(child), OrderRootType.CLASSES); + sdkUpdater.addRoot(getSdkRootVirtualFile(child), OrderRootType.CLASSES); } @NotNull diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java index 47ab071f2c6b..3b2f12b5a63a 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java @@ -29,7 +29,6 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.projectRoots.SdkTypeId; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.startup.StartupActivity; @@ -124,7 +123,7 @@ public class PythonSdkUpdater implements StartupActivity { for (final Sdk sdk : sdksToUpdate) { try { LOG.info("Performing background update of skeletons for SDK " + sdk.getHomePath()); - updateSdk(project, null, sdk, PythonSdkType.findSkeletonsPath(sdk)); + updateSdk(project, null, PySdkUpdater.fromSdkPath(sdk.getHomePath()), PythonSdkType.findSkeletonsPath(sdk)); } catch (InvalidSdkException e) { if (PythonSdkType.isVagrant(sdk)) { @@ -149,13 +148,14 @@ public class PythonSdkUpdater implements StartupActivity { }); } - public static void updateSdk(@Nullable Project project, @Nullable Component ownerComponent, @NotNull final Sdk sdk, String skeletonsPath) throws InvalidSdkException { - PySkeletonRefresher.refreshSkeletonsOfSdk(project, ownerComponent, skeletonsPath, sdk); // NOTE: whole thing would need a rename - if (!PySdkUtil.isRemote(sdk)) { - updateSysPath(sdk); + public static void updateSdk(@Nullable Project project, @Nullable Component ownerComponent, @NotNull final PySdkUpdater sdkUpdater, String skeletonsPath) + throws InvalidSdkException { + PySkeletonRefresher.refreshSkeletonsOfSdk(project, ownerComponent, skeletonsPath, sdkUpdater); // NOTE: whole thing would need a rename + if (!PySdkUtil.isRemote(sdkUpdater.getSdk())) { + updateSysPath(sdkUpdater); } else { - PyRemoteSdkAdditionalDataBase remoteSdkData = (PyRemoteSdkAdditionalDataBase)sdk.getSdkAdditionalData(); + PyRemoteSdkAdditionalDataBase remoteSdkData = (PyRemoteSdkAdditionalDataBase)sdkUpdater.getSdk().getSdkAdditionalData(); assert remoteSdkData != null; final List paths = Lists.newArrayList(); for (PathMappingSettings.PathMapping mapping : remoteSdkData.getPathMappings().getPathMappings()) { @@ -165,15 +165,15 @@ public class PythonSdkUpdater implements StartupActivity { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { - updateSdkPath(sdk, paths); + updateSdkPath(sdkUpdater, paths); } }); } } - private static void updateSysPath(@NotNull final Sdk sdk) throws InvalidSdkException { + private static void updateSysPath(@NotNull final PySdkUpdater sdkUpdater) throws InvalidSdkException { long start_time = System.currentTimeMillis(); - final List sysPath = PythonSdkType.getSysPath(sdk.getHomePath()); + final List sysPath = PythonSdkType.getSysPath(sdkUpdater.getHomePath()); final VirtualFile file = PyUserSkeletonsUtil.getUserSkeletonsDirectory(); if (file != null) { sysPath.add(file.getPath()); @@ -181,7 +181,7 @@ public class PythonSdkUpdater implements StartupActivity { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { - updateSdkPath(sdk, sysPath); + updateSdkPath(sdkUpdater, sysPath); } }); LOG.info("Updating sys.path took " + (System.currentTimeMillis() - start_time) + " ms"); @@ -190,29 +190,20 @@ public class PythonSdkUpdater implements StartupActivity { /** * Updates SDK based on sys.path and cleans legacy information up. */ - private static void updateSdkPath(@NotNull Sdk sdk, @NotNull List sysPath) { - final SdkModificator modificator = sdk.getSdkModificator(); - boolean changed = addNewSysPathEntries(sdk, modificator, sysPath); - changed = removeSourceRoots(sdk, modificator) || changed; - changed = removeDuplicateClassRoots(sdk, modificator) || changed; - changed = updateSkeletonsPath(sdk, modificator) || changed; - if (changed) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - modificator.commitChanges(); - } - }); - } + private static void updateSdkPath(@NotNull PySdkUpdater sdkUpdater, @NotNull List sysPath) { + addNewSysPathEntries(sdkUpdater, sysPath); + removeSourceRoots(sdkUpdater); + removeDuplicateClassRoots(sdkUpdater); + updateSkeletonsPath(sdkUpdater); } /** * Adds new CLASSES entries found in sys.path. */ - private static boolean addNewSysPathEntries(@NotNull Sdk sdk, @NotNull SdkModificator modificator, @NotNull List sysPath) { - final List oldRoots = Arrays.asList(sdk.getRootProvider().getFiles(OrderRootType.CLASSES)); - PythonSdkAdditionalData additionalData = sdk.getSdkAdditionalData() instanceof PythonSdkAdditionalData - ? (PythonSdkAdditionalData)sdk.getSdkAdditionalData() + private static boolean addNewSysPathEntries(@NotNull PySdkUpdater sdkUpdater, @NotNull List sysPath) { + final List oldRoots = Arrays.asList(sdkUpdater.getSdk().getRootProvider().getFiles(OrderRootType.CLASSES)); + PythonSdkAdditionalData additionalData = sdkUpdater.getSdk().getSdkAdditionalData() instanceof PythonSdkAdditionalData + ? (PythonSdkAdditionalData)sdkUpdater.getSdk().getSdkAdditionalData() : null; List newRoots = new ArrayList(); for (String root : sysPath) { @@ -225,7 +216,7 @@ public class PythonSdkUpdater implements StartupActivity { } if (!newRoots.isEmpty()) { for (String root : newRoots) { - PythonSdkType.addSdkRoot(modificator, root); + PythonSdkType.addSdkRoot(sdkUpdater, root); } return true; } @@ -235,13 +226,13 @@ public class PythonSdkUpdater implements StartupActivity { /** * Removes duplicate roots that have been added as the result of a bug with *.egg handling. */ - private static boolean removeDuplicateClassRoots(@NotNull Sdk sdk, @NotNull SdkModificator modificator) { - final List sourceRoots = Arrays.asList(sdk.getRootProvider().getFiles(OrderRootType.CLASSES)); + private static boolean removeDuplicateClassRoots(@NotNull PySdkUpdater sdkUpdater) { + final List sourceRoots = Arrays.asList(sdkUpdater.getSdk().getRootProvider().getFiles(OrderRootType.CLASSES)); final LinkedHashSet uniqueRoots = new LinkedHashSet(sourceRoots); if (uniqueRoots.size() != sourceRoots.size()) { - modificator.removeRoots(OrderRootType.CLASSES); + sdkUpdater.removeRoots(OrderRootType.CLASSES); for (VirtualFile root : uniqueRoots) { - modificator.addRoot(root, OrderRootType.CLASSES); + sdkUpdater.addRoot(root, OrderRootType.CLASSES); } return true; } @@ -251,10 +242,10 @@ public class PythonSdkUpdater implements StartupActivity { /** * Removes legacy SOURCES entries in Python SDK tables (PY-2891). */ - private static boolean removeSourceRoots(@NotNull Sdk sdk, @NotNull SdkModificator modificator) { - final VirtualFile[] sourceRoots = sdk.getRootProvider().getFiles(OrderRootType.SOURCES); + private static boolean removeSourceRoots(@NotNull PySdkUpdater sdkUpdater) { + final VirtualFile[] sourceRoots = sdkUpdater.getSdk().getRootProvider().getFiles(OrderRootType.SOURCES); if (sourceRoots.length > 0) { - modificator.removeRoots(OrderRootType.SOURCES); + sdkUpdater.removeRoots(OrderRootType.SOURCES); return true; } return false; @@ -263,31 +254,27 @@ public class PythonSdkUpdater implements StartupActivity { /** * Updates binary skeletons path in the Python SDK table. */ - private static boolean updateSkeletonsPath(@NotNull Sdk sdk, @NotNull SdkModificator modificator) { - boolean changed = false; - final String skeletonsPath = PythonSdkType.getSkeletonsPath(PathManager.getSystemPath(), sdk.getHomePath()); + private static void updateSkeletonsPath(@NotNull PySdkUpdater sdkUpdater) { + final String skeletonsPath = PythonSdkType.getSkeletonsPath(PathManager.getSystemPath(), sdkUpdater.getHomePath()); if (skeletonsPath != null) { final VirtualFile skeletonsDir = StandardFileSystems.local().refreshAndFindFileByPath(skeletonsPath); if (skeletonsDir != null) { - LOG.info("Binary skeletons directory for SDK \"" + sdk.getName() + "\" (" + sdk.getHomePath() + "): " + skeletonsDir.getPath()); - final List sourceRoots = Arrays.asList(sdk.getRootProvider().getFiles(OrderRootType.CLASSES)); + LOG.info("Binary skeletons directory for SDK \"" + sdkUpdater.getSdk().getName() + "\" (" + sdkUpdater.getHomePath() + "): " + skeletonsDir.getPath()); + final List sourceRoots = Arrays.asList(sdkUpdater.getSdk().getRootProvider().getFiles(OrderRootType.CLASSES)); boolean skeletonsDirFound = false; - for (VirtualFile root : sourceRoots) { + for (final VirtualFile root : sourceRoots) { if (root.equals(skeletonsDir)) { skeletonsDirFound = true; } if (PythonSdkType.isSkeletonsPath(root.getPath()) && !skeletonsDirFound) { - modificator.removeRoot(root, OrderRootType.CLASSES); - changed = true; + sdkUpdater.addRoot(root, OrderRootType.CLASSES); } } if (!skeletonsDirFound) { - modificator.addRoot(skeletonsDir, OrderRootType.CLASSES); - changed = true; + sdkUpdater.addRoot(skeletonsDir, OrderRootType.CLASSES); } } } - return changed; } private static boolean wasOldRoot(@NotNull String root, @NotNull Collection oldRoots) { diff --git a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java index c9c7d636a1a1..6549a3f49114 100644 --- a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java +++ b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java @@ -47,6 +47,7 @@ import com.jetbrains.python.packaging.PyPackageManager; import com.jetbrains.python.psi.resolve.PythonSdkPathCache; import com.jetbrains.python.remote.PythonRemoteInterpreterManager; import com.jetbrains.python.sdk.InvalidSdkException; +import com.jetbrains.python.sdk.PySdkUpdater; import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NonNls; @@ -111,25 +112,25 @@ public class PySkeletonRefresher { public static void refreshSkeletonsOfSdk(@Nullable Project project, Component ownerComponent, String skeletonsPath, - @NotNull Sdk sdk) + @NotNull PySdkUpdater sdkUpdater) throws InvalidSdkException { final Map> errors = new TreeMap>(); final List failedSdks = new SmartList(); final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); - final String homePath = sdk.getHomePath(); + final String homePath = sdkUpdater.getHomePath(); if (skeletonsPath == null) { LOG.info("Could not find skeletons path for SDK path " + homePath); } else { LOG.info("Refreshing skeletons for " + homePath); SkeletonVersionChecker checker = new SkeletonVersionChecker(0); // this default version won't be used - final PySkeletonRefresher refresher = new PySkeletonRefresher(project, ownerComponent, sdk, skeletonsPath, indicator, null); + final PySkeletonRefresher refresher = new PySkeletonRefresher(project, ownerComponent, sdkUpdater.getSdk(), skeletonsPath, indicator, null); changeGeneratingSkeletons(1); try { List sdkErrors = refresher.regenerateSkeletons(checker); if (sdkErrors.size() > 0) { - String sdkName = sdk.getName(); + String sdkName = sdkUpdater.getSdk().getName(); List knownErrors = errors.get(sdkName); if (knownErrors == null) { errors.put(sdkName, sdkErrors); diff --git a/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java b/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java index c81772187191..33b89821ce19 100644 --- a/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java +++ b/python/testSrc/com/jetbrains/env/python/testing/PythonUnitTestingTest.java @@ -144,10 +144,10 @@ public class PythonUnitTestingTest extends PyEnvTestCase { @NotNull final String stderr, @NotNull final String all) { final List fileNames = runner.getHighlightedStringsInConsole().getSecond(); - Assert.assertThat(String.format("Wrong number of highlighted entries(%s) in the following output: %s", + Assert.assertTrue(String.format("Not enough highlighted entries(%s) in the following output: %s", StringUtil.join(fileNames, ","), runner.getAllConsoleText()), - fileNames, Matchers.hasSize(3)); + fileNames.size() >= 3); // UnitTest highlights file name Assert.assertThat("Bad line highlighted", fileNames, Matchers.everyItem(Matchers.endsWith(fileName))); } diff --git a/python/testSrc/com/jetbrains/python/PythonMockSdk.java b/python/testSrc/com/jetbrains/python/PythonMockSdk.java index 0acdbc062b9f..f9de2dad53a2 100644 --- a/python/testSrc/com/jetbrains/python/PythonMockSdk.java +++ b/python/testSrc/com/jetbrains/python/PythonMockSdk.java @@ -26,6 +26,7 @@ import com.intellij.psi.stubs.StubUpdatingIndex; import com.intellij.util.indexing.FileBasedIndex; import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil; import com.jetbrains.python.psi.stubs.PyModuleNameIndex; +import com.jetbrains.python.sdk.PySdkUpdater; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NonNls; @@ -72,7 +73,7 @@ public class PythonMockSdk { sdkModificator.addRoot(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(libPath), OrderRootType.CLASSES); } - PyUserSkeletonsUtil.addUserSkeletonsRoot(sdkModificator); + PyUserSkeletonsUtil.addUserSkeletonsRoot(PySdkUpdater.fromSdkModificator(sdk, sdkModificator)); String mock_stubs_path = mock_path + PythonSdkType.SKELETON_DIR_NAME; sdkModificator.addRoot(LocalFileSystem.getInstance().refreshAndFindFileByPath(mock_stubs_path), PythonSdkType.BUILTIN_ROOT_TYPE); diff --git a/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java b/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java index 882d603c32aa..35dc7b2e3d49 100644 --- a/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java +++ b/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java @@ -14,6 +14,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.UsefulTestCase; import com.jetbrains.python.sdk.InvalidSdkException; +import com.jetbrains.python.sdk.PySdkUpdater; import com.jetbrains.python.sdk.PythonSdkType; import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher; import com.jetbrains.python.sdk.skeletons.SkeletonVersionChecker; @@ -114,7 +115,7 @@ public final class PyTestSdkTools { modificator.removeRoots(OrderRootType.CLASSES); for (final String path : PythonSdkType.getSysPathsFromScript(sdk.getHomePath())) { - PythonSdkType.addSdkRoot(modificator, path); + PythonSdkType.addSdkRoot(PySdkUpdater.fromSdkModificator(sdk, modificator), path); } if (!addSkeletons) { UsefulTestCase.edt(new Runnable() { @@ -130,7 +131,7 @@ public final class PyTestSdkTools { final File skeletonsDir = new File(tempDir, PythonSdkType.SKELETON_DIR_NAME); FileUtil.createDirectory(skeletonsDir); final String skeletonsPath = skeletonsDir.toString(); - PythonSdkType.addSdkRoot(modificator, skeletonsPath); + PythonSdkType.addSdkRoot(PySdkUpdater.fromSdkModificator(sdk, modificator), skeletonsPath); UsefulTestCase.edt(new Runnable() { @Override diff --git a/xml/impl/src/com/intellij/javaee/MapExternalResourceDialog.java b/xml/impl/src/com/intellij/javaee/MapExternalResourceDialog.java index b1073afa3477..2878567374ae 100644 --- a/xml/impl/src/com/intellij/javaee/MapExternalResourceDialog.java +++ b/xml/impl/src/com/intellij/javaee/MapExternalResourceDialog.java @@ -77,10 +77,58 @@ public class MapExternalResourceDialog extends DialogWrapper { private final FileSystemTreeImpl myExplorer; private String myLocation; - public MapExternalResourceDialog(String uri, @NotNull Project project, @Nullable PsiFile file, @Nullable String location) { + public MapExternalResourceDialog(String uri, @Nullable Project project, @Nullable PsiFile file, @Nullable String location) { super(project); setTitle("Map External Resource"); myUri.setText(uri); + myUri.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + validateInput(); + } + }); + + myExplorer = new FileSystemTreeImpl(project, new FileChooserDescriptor(true, false, false, false, true, false)); + Disposer.register(getDisposable(), myExplorer); + + myExplorer.addListener(new FileSystemTree.Listener() { + @Override + public void selectionChanged(List selection) { + validateInput(); + } + }, myExplorer); + + MouseAdapter mouseAdapter = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() > 1 && isOKActionEnabled()) { + doOKAction(); + } + } + }; + myExplorer.getTree().addMouseListener(mouseAdapter); + + myExplorerPanel.add(ScrollPaneFactory.createScrollPane(myExplorer.getTree()), BorderLayout.CENTER); + + AnAction actionGroup = ActionManager.getInstance().getAction("FileChooserToolbar"); + ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, (ActionGroup)actionGroup, true); + toolbar.setTargetComponent(myExplorerPanel); + myExplorerPanel.add(toolbar.getComponent(), BorderLayout.NORTH); + + if (project != null) { + setupSchemasTab(uri, project, file, location, mouseAdapter); + } + else { + myTabs.removeTabAt(0); + } + init(); + } + + private void setupSchemasTab(String uri, + @NotNull Project project, + @Nullable PsiFile file, + @Nullable String location, + MouseAdapter mouseAdapter) { DefaultMutableTreeNode root = new DefaultMutableTreeNode(); mySchemasTree.setModel(new DefaultTreeModel(root)); @@ -120,22 +168,7 @@ public class MapExternalResourceDialog extends DialogWrapper { renderer.setFont(EditorColorsManager.getInstance().getGlobalScheme().getFont(EditorFontType.PLAIN)); mySchemasTree.setCellRenderer(renderer); - MouseAdapter mouseAdapter = new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() > 1 && isOKActionEnabled()) { - doOKAction(); - } - } - }; mySchemasTree.addMouseListener(mouseAdapter); - - myUri.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(DocumentEvent e) { - validateInput(); - } - }); mySchemasTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { @Override public void valueChanged(TreeSelectionEvent e) { @@ -143,24 +176,6 @@ public class MapExternalResourceDialog extends DialogWrapper { } }); - myExplorer = new FileSystemTreeImpl(project, new FileChooserDescriptor(true, false, false, false, true, false)); - Disposer.register(getDisposable(), myExplorer); - - myExplorer.addListener(new FileSystemTree.Listener() { - @Override - public void selectionChanged(List selection) { - validateInput(); - } - }, myExplorer); - myExplorer.getTree().addMouseListener(mouseAdapter); - - myExplorerPanel.add(ScrollPaneFactory.createScrollPane(myExplorer.getTree()), BorderLayout.CENTER); - - AnAction actionGroup = ActionManager.getInstance().getAction("FileChooserToolbar"); - ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, (ActionGroup)actionGroup, true); - toolbar.setTargetComponent(myExplorerPanel); - myExplorerPanel.add(toolbar.getComponent(), BorderLayout.NORTH); - PsiFile schema = null; if (file != null) { schema = XmlUtil.findNamespaceByLocation(file, uri); @@ -188,7 +203,6 @@ public class MapExternalResourceDialog extends DialogWrapper { PropertiesComponent.getInstance().setValue(MAP_EXTERNAL_RESOURCE_SELECTED_TAB, Integer.toString(myTabs.getSelectedIndex())); } }); - init(); } @Override @@ -220,7 +234,7 @@ public class MapExternalResourceDialog extends DialogWrapper { public String getResourceLocation() { if (myLocation != null) return myLocation; - if (myTabs.getSelectedIndex() == 0) { + if (myTabs.getTabCount() > 1 && myTabs.getSelectedIndex() == 0) { TreePath path = mySchemasTree.getSelectionPath(); if (path == null) return null; Object object = ((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject();