diff --git a/build/scripts/download_kotlin.gant b/build/scripts/download_kotlin.gant index 7fa565e439a7..c601a822034d 100644 --- a/build/scripts/download_kotlin.gant +++ b/build/scripts/download_kotlin.gant @@ -321,6 +321,6 @@ class TeamCityBuildLocator { String getDownloadUrl(String buildNumber) { String encodedBuildNumber = URLEncoder.encode(buildNumber, "UTF-8") - return "$host/guestAuth/repository/download/$buildTypeId/$encodedBuildNumber/kotlin-plugin-${encodedBuildNumber}-IJ2016.3-1.zip" + return "$host/guestAuth/repository/download/$buildTypeId/$encodedBuildNumber/kotlin-plugin-1.0.5-release-IJ2016.3-2.zip" } } diff --git a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java index 86d339aee6cb..bcaf1b8a94a4 100644 --- a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java +++ b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java @@ -139,7 +139,7 @@ public class JavaParametersUtil { parameters.configureByProject(project, classPathType, createProjectJdk(project, jreHome)); } - private static Sdk createModuleJdk(final Module module, boolean productionOnly, @Nullable String jreHome) throws CantRunException { + public static Sdk createModuleJdk(final Module module, boolean productionOnly, @Nullable String jreHome) throws CantRunException { return jreHome == null ? JavaParameters.getValidJdkToRunModule(module, productionOnly) : createAlternativeJdk(jreHome); } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/JoinDeclarationAndAssignmentAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/JoinDeclarationAndAssignmentAction.java index ac595190f917..a388d6f09cdd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/JoinDeclarationAndAssignmentAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/JoinDeclarationAndAssignmentAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -21,6 +21,7 @@ import com.intellij.codeInsight.editorActions.DeclarationJoinLinesHandler; import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; import com.intellij.codeInspection.RemoveInitializerFix; import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; @@ -100,6 +101,11 @@ public class JoinDeclarationAndAssignmentAction extends PsiElementBaseIntentionA return null; } + @Override + public boolean startInWriteAction() { + return false; + } + @Override public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return; @@ -112,8 +118,10 @@ public class JoinDeclarationAndAssignmentAction extends PsiElementBaseIntentionA if (initializer != null && assignmentExpression.getOperationTokenType() == JavaTokenType.EQ) { RemoveInitializerFix.sideEffectAwareRemove(project, initializer, initializer, variable); } - final PsiExpression initializerExpression = DeclarationJoinLinesHandler.getInitializerExpression(variable, assignmentExpression); - variable.setInitializer(initializerExpression); - assignmentExpression.delete(); + WriteAction.run(() -> { + final PsiExpression initializerExpression = DeclarationJoinLinesHandler.getInitializerExpression(variable, assignmentExpression); + variable.setInitializer(initializerExpression); + assignmentExpression.delete(); + }); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java index 6c79ed10075c..173311616a04 100644 --- a/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java @@ -17,6 +17,7 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInsight.PsiEquivalenceUtil; import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.codeInspection.util.LambdaGenerationUtil; import com.intellij.codeInspection.util.OptionalUtil; @@ -33,10 +34,9 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.PsiUtil; import com.siyeh.ig.psiutils.BoolUtils; +import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.ControlFlowUtils; -import com.siyeh.ig.psiutils.EquivalenceChecker; import com.siyeh.ig.psiutils.ExpressionUtils; -import one.util.streamex.StreamEx; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -55,6 +55,18 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo new TernaryCase() }; + private enum ProblemType { + WARNING, INFO, NONE; + + void registerProblem(ProblemsHolder holder, PsiExpression condition, OptionalIfPresentCase scenario) { + if(this != NONE) { + holder.registerProblem(condition, "Can be replaced with single expression in functional style", + this == INFO ? ProblemHighlightType.INFORMATION : ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + new OptionalIfPresentFix(scenario)); + } + } + } + @NotNull @Override public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) { @@ -100,10 +112,7 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo void check(PsiExpression condition, PsiVariable optionalVariable, PsiElement thenElement, PsiElement elseElement) { for (OptionalIfPresentCase scenario : CASES) { - if (scenario.isApplicable(optionalVariable, thenElement, elseElement)) { - holder.registerProblem(condition, "Can be replaced with single expression in functional style", - new OptionalIfPresentFix(scenario)); - } + scenario.getProblemType(optionalVariable, thenElement, elseElement).registerProblem(holder, condition, scenario); } } }; @@ -162,13 +171,16 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo ExpressionUtils.isReferenceTo(methodExpression.getQualifierExpression(), variable); } - @Contract("_, null, _ -> false") - static boolean isOptionalLambdaCandidate(PsiVariable optionalVariable, PsiExpression lambdaCandidate, PsiExpression falseExpression) { - if (lambdaCandidate == null) return false; - if (ExpressionUtils.isReferenceTo(lambdaCandidate, optionalVariable) && OptionalUtil.isOptionalEmptyCall(falseExpression)) return true; - if (!ExceptionUtil.getThrownCheckedExceptions(lambdaCandidate).isEmpty()) return false; + @NotNull + static ProblemType getTypeByLambdaCandidate(PsiVariable optionalVariable, PsiElement lambdaCandidate, PsiExpression falseExpression) { + if (lambdaCandidate == null) return ProblemType.NONE; + if (lambdaCandidate instanceof PsiReferenceExpression && + ((PsiReferenceExpression)lambdaCandidate).isReferenceTo(optionalVariable) && OptionalUtil.isOptionalEmptyCall(falseExpression)) { + return ProblemType.WARNING; + } + if (!ExceptionUtil.getThrownCheckedExceptions(lambdaCandidate).isEmpty()) return ProblemType.NONE; Ref hasOptionalReference = new Ref<>(Boolean.FALSE); - return PsiTreeUtil.processElements(lambdaCandidate, e -> { + boolean hasNoBadRefs = PsiTreeUtil.processElements(lambdaCandidate, e -> { if (!(e instanceof PsiReferenceExpression)) return true; PsiElement element = ((PsiReferenceExpression)e).resolve(); if (!(element instanceof PsiVariable)) return true; @@ -178,11 +190,14 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo return isOptionalGetCall(e.getParent().getParent(), optionalVariable); } return HighlightControlFlowUtil.isEffectivelyFinal((PsiVariable)element, lambdaCandidate, null); - }) && hasOptionalReference.get(); + }); + if(!hasNoBadRefs) return ProblemType.NONE; + if(hasOptionalReference.get() && lambdaCandidate instanceof PsiExpression) return ProblemType.WARNING; + return ProblemType.INFO; } @NotNull - static String generateOptionalLambda(PsiElementFactory factory, PsiVariable optionalVariable, PsiExpression trueValue) { + static String generateOptionalLambda(PsiElementFactory factory, CommentTracker ct, PsiVariable optionalVariable, PsiElement trueValue) { PsiType type = optionalVariable.getType(); JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(trueValue.getProject()); SuggestedNameInfo info = javaCodeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type); @@ -190,16 +205,23 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo info = javaCodeStyleManager.suggestVariableName(VariableKind.PARAMETER, "value", null, type); } String paramName = javaCodeStyleManager.suggestUniqueVariableName(info, trueValue, true).names[0]; + if(trueValue instanceof PsiExpressionStatement) { + trueValue = ((PsiExpressionStatement)trueValue).getExpression(); + } + ct.markUnchanged(trueValue); PsiElement copy = trueValue.copy(); for (PsiElement getCall : PsiTreeUtil.collectElements(copy, e -> isOptionalGetCall(e, optionalVariable))) { PsiElement result = getCall.replace(factory.createIdentifier(paramName)); if (copy == getCall) copy = result; } + if(copy instanceof PsiStatement && !(copy instanceof PsiBlockStatement)) { + return paramName + "->{" + copy.getText()+"}"; + } return paramName + "->" + copy.getText(); } static String generateOptionalUnwrap(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiExpression trueValue, PsiExpression falseValue, PsiType targetType) { @@ -210,10 +232,14 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo if (ExpressionUtils.isReferenceTo(falseValue, optionalVariable)) { falseValue = factory.createExpressionFromText(CommonClassNames.JAVA_UTIL_OPTIONAL + ".empty()", falseValue); } - String lambdaText = generateOptionalLambda(factory, optionalVariable, trueValue); + String lambdaText = generateOptionalLambda(factory, ct, optionalVariable, trueValue); PsiLambdaExpression lambda = (PsiLambdaExpression)factory.createExpressionFromText(lambdaText, trueValue); return OptionalUtil.generateOptionalUnwrap(optionalVariable.getName(), lambda.getParameterList().getParameters()[0], - (PsiExpression)lambda.getBody(), falseValue, targetType, true); + (PsiExpression)lambda.getBody(), ct.markUnchanged(falseValue), targetType, true); + } + + static boolean isSimpleOrUnchecked(PsiExpression expression) { + return ExpressionUtils.isSimpleExpression(expression) || LambdaGenerationUtil.canBeUncheckedLambda(expression); } static class OptionalIfPresentFix implements LocalQuickFix { @@ -252,24 +278,17 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo thenElement = invert ? ((PsiConditionalExpression)cond).getElseExpression() : ((PsiConditionalExpression)cond).getThenExpression(); elseElement = invert ? ((PsiConditionalExpression)cond).getThenExpression() : ((PsiConditionalExpression)cond).getElseExpression(); } else return; - if (!myScenario.isApplicable(optionalVariable, thenElement, elseElement)) return; + if (myScenario.getProblemType(optionalVariable, thenElement, elseElement) == ProblemType.NONE) return; if (!FileModificationService.getInstance().preparePsiElementForWrite(element.getContainingFile())) return; PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - PsiElement parent = cond.getParent(); - StreamEx.of(cond, thenElement, elseElement).nonNull() - .flatCollection(st -> PsiTreeUtil.findChildrenOfType(st, PsiComment.class)) - .distinct() - .forEach(comment -> { - parent.addBefore(comment, cond); - comment.delete(); - }); - String replacementText = myScenario.generateReplacement(factory, optionalVariable, thenElement, elseElement); - if (thenElement != null && !PsiTreeUtil.isAncestor(cond, thenElement, true)) thenElement.delete(); - if (elseElement != null && !PsiTreeUtil.isAncestor(cond, elseElement, true)) elseElement.delete(); + CommentTracker ct = new CommentTracker(); + String replacementText = myScenario.generateReplacement(factory, ct, optionalVariable, thenElement, elseElement); + if (thenElement != null && !PsiTreeUtil.isAncestor(cond, thenElement, true)) ct.delete(thenElement); + if (elseElement != null && !PsiTreeUtil.isAncestor(cond, elseElement, true)) ct.delete(elseElement); PsiElement replacement = cond instanceof PsiExpression ? factory.createExpressionFromText(replacementText, cond) : factory.createStatementFromText(replacementText, cond); - PsiElement result = cond.replace(replacement); + PsiElement result = ct.replaceAndRestoreComments(cond, replacement); LambdaCanBeMethodReferenceInspection.replaceAllLambdasWithMethodReferences(result); PsiDiamondTypeUtil.removeRedundantTypeArguments(result); CodeStyleManager.getInstance(project).reformat(result); @@ -277,28 +296,27 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo } interface OptionalIfPresentCase { - boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement); + ProblemType getProblemType(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement); String generateReplacement(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement); } static class ReturnCase implements OptionalIfPresentCase { @Override - public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { - if (!(trueElement instanceof PsiReturnStatement) || !(falseElement instanceof PsiReturnStatement)) return false; + public ProblemType getProblemType(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + if (!(trueElement instanceof PsiReturnStatement) || !(falseElement instanceof PsiReturnStatement)) return ProblemType.NONE; PsiExpression falseValue = ((PsiReturnStatement)falseElement).getReturnValue(); - if (!ExpressionUtils.isSimpleExpression(falseValue) && - !LambdaGenerationUtil.canBeUncheckedLambda(falseValue)) return false; PsiExpression trueValue = ((PsiReturnStatement)trueElement).getReturnValue(); - return isOptionalLambdaCandidate(optionalVariable, trueValue, falseValue); + if (!isSimpleOrUnchecked(falseValue)) return ProblemType.NONE; + return getTypeByLambdaCandidate(optionalVariable, trueValue, falseValue); } @Override public String generateReplacement(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { PsiExpression trueValue = ((PsiReturnStatement)trueElement).getReturnValue(); @@ -306,30 +324,29 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo LOG.assertTrue(trueValue != null); LOG.assertTrue(falseValue != null); return "return " + - generateOptionalUnwrap(factory, optionalVariable, trueValue, falseValue, PsiTypesUtil.getMethodReturnType(trueElement)) + + generateOptionalUnwrap(factory, ct, optionalVariable, trueValue, falseValue, PsiTypesUtil.getMethodReturnType(trueElement)) + ";"; } } static class AssignmentCase implements OptionalIfPresentCase { @Override - public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + public ProblemType getProblemType(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { PsiAssignmentExpression trueAssignment = ExpressionUtils.getAssignment(trueElement); PsiAssignmentExpression falseAssignment = ExpressionUtils.getAssignment(falseElement); - if (trueAssignment == null || - falseAssignment == null || - !EquivalenceChecker.getCanonicalPsiEquivalence() - .expressionsAreEquivalent(trueAssignment.getLExpression(), falseAssignment.getLExpression()) || - !isOptionalLambdaCandidate(optionalVariable, trueAssignment.getRExpression(), falseAssignment.getRExpression())) { - return false; + if (trueAssignment == null || falseAssignment == null) return ProblemType.NONE; + PsiExpression falseVal = falseAssignment.getRExpression(); + PsiExpression trueVal = trueAssignment.getRExpression(); + if (PsiEquivalenceUtil.areElementsEquivalent(trueAssignment.getLExpression(), falseAssignment.getLExpression()) && + isSimpleOrUnchecked(falseVal)) { + return getTypeByLambdaCandidate(optionalVariable, trueVal, falseVal); } - return ExpressionUtils.isSimpleExpression(falseAssignment.getRExpression()) || - LambdaGenerationUtil.canBeUncheckedLambda(falseAssignment.getRExpression()); + return ProblemType.NONE; } @Override public String generateReplacement(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { PsiAssignmentExpression trueAssignment = ExpressionUtils.getAssignment(trueElement); @@ -340,49 +357,51 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo PsiExpression trueValue = trueAssignment.getRExpression(); PsiExpression falseValue = falseAssignment.getRExpression(); LOG.assertTrue(falseValue != null); - return lValue.getText() + " = " + generateOptionalUnwrap(factory, optionalVariable, trueValue, falseValue, lValue.getType()) + ";"; + return lValue.getText() + " = " + generateOptionalUnwrap(factory, ct, optionalVariable, trueValue, falseValue, lValue.getType()) + ";"; } } static class TernaryCase implements OptionalIfPresentCase { @Override - public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { - if(!(trueElement instanceof PsiExpression) || !(falseElement instanceof PsiExpression)) return false; + public ProblemType getProblemType(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + if(!(trueElement instanceof PsiExpression) || !(falseElement instanceof PsiExpression)) return ProblemType.NONE; PsiExpression trueExpression = (PsiExpression)trueElement; PsiExpression falseExpression = (PsiExpression)falseElement; - return isOptionalLambdaCandidate(optionalVariable, trueExpression, falseExpression) && - (ExpressionUtils.isSimpleExpression(falseExpression) || LambdaGenerationUtil.canBeUncheckedLambda(falseExpression)); + return (isSimpleOrUnchecked(falseExpression)) ? + getTypeByLambdaCandidate(optionalVariable, trueExpression, falseExpression) : ProblemType.NONE; } @Override public String generateReplacement(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { PsiExpression ternary = PsiTreeUtil.getParentOfType(trueElement, PsiConditionalExpression.class); LOG.assertTrue(ternary != null); PsiExpression trueExpression = (PsiExpression)trueElement; PsiExpression falseExpression = (PsiExpression)falseElement; - return generateOptionalUnwrap(factory, optionalVariable, trueExpression, falseExpression, ternary.getType()); + return generateOptionalUnwrap(factory, ct, optionalVariable, trueExpression, falseExpression, ternary.getType()); } } static class ConsumerCase implements OptionalIfPresentCase { @Override - public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { - if (falseElement != null && !(falseElement instanceof PsiEmptyStatement)) return false; - if (!(trueElement instanceof PsiExpressionStatement)) return false; - PsiExpression expression = ((PsiExpressionStatement)trueElement).getExpression(); - return isOptionalLambdaCandidate(optionalVariable, expression, null) && !isOptionalGetCall(expression, optionalVariable); + public ProblemType getProblemType(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + if (falseElement != null && !(falseElement instanceof PsiEmptyStatement)) return ProblemType.NONE; + if (trueElement instanceof PsiExpressionStatement) { + PsiExpression expression = ((PsiExpressionStatement)trueElement).getExpression(); + if(isOptionalGetCall(expression, optionalVariable)) return ProblemType.NONE; + trueElement = expression; + } + return getTypeByLambdaCandidate(optionalVariable, trueElement, null); } @Override public String generateReplacement(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { - PsiExpression expression = ((PsiExpressionStatement)trueElement).getExpression(); - return optionalVariable.getName() + ".ifPresent(" + generateOptionalLambda(factory, optionalVariable, expression) + ");"; + return optionalVariable.getName() + ".ifPresent(" + generateOptionalLambda(factory, ct, optionalVariable, trueElement) + ");"; } } } diff --git a/java/java-impl/src/com/intellij/codeInspection/RemoveAssignmentFix.java b/java/java-impl/src/com/intellij/codeInspection/RemoveAssignmentFix.java index d2d962623c7b..5bd514211054 100644 --- a/java/java-impl/src/com/intellij/codeInspection/RemoveAssignmentFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/RemoveAssignmentFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -17,6 +17,7 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.editorActions.DeclarationJoinLinesHandler; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; @@ -49,11 +50,14 @@ public class RemoveAssignmentFix extends RemoveInitializerFix { final PsiElement gParent = parent.getParent(); if ((gParent instanceof PsiExpression || gParent instanceof PsiExpressionList || gParent instanceof PsiReturnStatement) && rExpression != null) { if (!FileModificationService.getInstance().prepareFileForWrite(gParent.getContainingFile())) return; - if (gParent instanceof PsiParenthesizedExpression) { - gParent.replace(rExpression); - } else { - parent.replace(rExpression); - } + PsiExpression finalRExpr = rExpression; + WriteAction.run(() -> { + if (gParent instanceof PsiParenthesizedExpression) { + gParent.replace(finalRExpr); + } else { + parent.replace(finalRExpr); + } + }); return; } diff --git a/java/java-impl/src/com/intellij/codeInspection/RemoveInitializerFix.java b/java/java-impl/src/com/intellij/codeInspection/RemoveInitializerFix.java index 6ffd46aca6df..ad7f585441d3 100644 --- a/java/java-impl/src/com/intellij/codeInspection/RemoveInitializerFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/RemoveInitializerFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -18,14 +18,13 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.impl.quickfix.RemoveUnusedVariableFix; import com.intellij.codeInsight.daemon.impl.quickfix.RemoveUnusedVariableUtil; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiExpressionTrimRenderer; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.Function; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -50,6 +49,11 @@ public class RemoveInitializerFix implements LocalQuickFix { sideEffectAwareRemove(project, (PsiExpression)psiInitializer, psiInitializer, variable); } + @Override + public boolean startInWriteAction() { + return false; + } + public static void sideEffectAwareRemove(Project project, PsiExpression psiInitializer, PsiElement elementToDelete, @@ -59,7 +63,7 @@ public class RemoveInitializerFix implements LocalQuickFix { final PsiElement declaration = variable.getParent(); final List sideEffects = new ArrayList<>(); boolean hasSideEffects = RemoveUnusedVariableUtil.checkSideEffects(psiInitializer, variable, sideEffects); - RemoveUnusedVariableUtil.RemoveMode res = RemoveUnusedVariableUtil.RemoveMode.DELETE_ALL; + RemoveUnusedVariableUtil.RemoveMode res; if (hasSideEffects) { hasSideEffects = PsiUtil.isStatement(psiInitializer); PsiTypeElement typeElement = variable.getTypeElement(); @@ -71,7 +75,10 @@ public class RemoveInitializerFix implements LocalQuickFix { PsiExpressionTrimRenderer.render(psiInitializer) ); } - try { + else { + res = RemoveUnusedVariableUtil.RemoveMode.DELETE_ALL; + } + WriteAction.run(() -> { if (res == RemoveUnusedVariableUtil.RemoveMode.DELETE_ALL) { elementToDelete.delete(); } @@ -81,14 +88,12 @@ public class RemoveInitializerFix implements LocalQuickFix { final PsiElement parent = elementToDelete.getParent(); if (parent instanceof PsiExpressionStatement) { parent.replace(statementFromText); - } else { + } + else { declaration.getParent().addBefore(statementFromText, declaration); elementToDelete.delete(); } } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } + }); } } diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/ReferenceChainLink.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/ReferenceChainLink.java index 15ccb80fa2b0..31c6527bc090 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/ReferenceChainLink.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/ReferenceChainLink.java @@ -29,8 +29,11 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; /** * @author peter @@ -83,8 +86,7 @@ public class ReferenceChainLink { List candidates = new ArrayList<>(); AtomicInteger count = new AtomicInteger(); Processor processor = member -> { - if (canBeAccessible(placeFile, member) && (!(member instanceof PsiMethod) || - ApproximateResolver.canHaveArgCount((PsiMethod)member, argCount))) { + if (!(member instanceof PsiMethod && !ApproximateResolver.canHaveArgCount((PsiMethod)member, argCount))) { candidates.add(member); } return count.incrementAndGet() < 42; @@ -112,7 +114,7 @@ public class ReferenceChainLink { return null; } - return candidates; + return candidates.stream().filter(candidate -> canBeAccessible(placeFile, candidate)).collect(Collectors.toList()); } private static boolean canBeAccessible(VirtualFile placeFile, PsiMember member) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java index d450c1fb02b5..9166725178d7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java @@ -16,6 +16,9 @@ package com.intellij.psi.impl; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.ExtensionPoint; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.extensions.SimpleSmartExtensionPoint; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; @@ -48,7 +51,7 @@ import java.util.concurrent.ConcurrentMap; public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { private static final Logger LOG = Logger.getInstance(JavaPsiFacadeImpl.class); - private final PsiElementFinder[] myElementFinders; + private final SimpleSmartExtensionPoint myElementFinders; private final PsiConstantEvaluationHelper myConstantEvaluationHelper; private final ConcurrentMap myPackageCache = ContainerUtil.createConcurrentSoftValueMap(); private final ConcurrentMap> myClassCache = ContainerUtil.createConcurrentWeakKeySoftValueMap(); @@ -82,7 +85,13 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { } DummyHolderFactory.setFactory(new JavaDummyHolderFactory()); - myElementFinders = calcFinders(); + myElementFinders = new SimpleSmartExtensionPoint(Collections.emptyList()) { + @NotNull + @Override + protected ExtensionPoint getExtensionPoint() { + return Extensions.getArea(myProject).getExtensionPoint(PsiElementFinder.EP_NAME); + } + }; } @Override @@ -115,7 +124,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return null; } - PsiElementFinder[] finders = finders(); + List finders = finders(); Condition classesFilter = getFilterFromFinders(scope, finders); for (PsiElementFinder finder : finders) { @@ -156,7 +165,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return findClassesInDumbMode(qualifiedName, scope); } - PsiElementFinder[] finders = finders(); + List finders = finders(); Condition classesFilter = getFilterFromFinders(scope, finders); List result = null; @@ -171,7 +180,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return result == null || result.isEmpty() ? PsiClass.EMPTY_ARRAY : result.toArray(new PsiClass[result.size()]); } - private static Condition getFilterFromFinders(@NotNull GlobalSearchScope scope, @NotNull PsiElementFinder[] finders) { + private static Condition getFilterFromFinders(@NotNull GlobalSearchScope scope, @NotNull List finders) { Condition filter = null; for (PsiElementFinder finder : finders) { Condition finderFilter = finder.getClassesFilter(scope); @@ -187,13 +196,8 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return dumbService.isDumb() && dumbService.isAlternativeResolveEnabled(); } - private PsiElementFinder[] finders() { - return myElementFinders; - } - - @NotNull - protected PsiElementFinder[] calcFinders() { - return myProject.getExtensions(PsiElementFinder.EP_NAME); + private List finders() { + return myElementFinders.getExtensions(); } @Override @@ -220,14 +224,8 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { } @NotNull - private PsiElementFinder[] filteredFinders() { - DumbService dumbService = DumbService.getInstance(getProject()); - PsiElementFinder[] finders = finders(); - if (dumbService.isDumb()) { - List list = dumbService.filterByDumbAwareness(finders); - finders = list.toArray(new PsiElementFinder[list.size()]); - } - return finders; + private List filteredFinders() { + return DumbService.getInstance(getProject()).filterByDumbAwareness(finders()); } @Override @@ -259,7 +257,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { @NotNull public PsiClass[] getClasses(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { - PsiElementFinder[] finders = filteredFinders(); + List finders = filteredFinders(); Condition classesFilter = getFilterFromFinders(scope, finders); List result = null; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java index e3fc076fab1c..35ec88e550aa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java @@ -35,10 +35,7 @@ import com.intellij.psi.impl.java.stubs.PsiJavaFileStub; import com.intellij.psi.impl.source.resolve.ClassResolverProcessor; import com.intellij.psi.impl.source.resolve.SymbolCollectingProcessor; import com.intellij.psi.impl.source.tree.JavaElementType; -import com.intellij.psi.scope.ElementClassHint; -import com.intellij.psi.scope.JavaScopeProcessorEvent; -import com.intellij.psi.scope.NameHint; -import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.scope.*; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; @@ -348,11 +345,7 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava // check in current package final PsiPackage aPackage = JavaPsiFacade.getInstance(myManager.getProject()).findPackage(getPackageName()); - if (aPackage != null) { - if (!aPackage.processDeclarations(processor, state, null, place)) { - return false; - } - } + if (aPackage != null && !processPackageDeclarations(processor, state, place, aPackage)) return false; // on-demand processing for (PsiImportStatement statement : importStatements) { @@ -414,6 +407,31 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava return true; } + private static boolean processPackageDeclarations(PsiScopeProcessor processor, + @NotNull ResolveState state, + PsiElement place, + @NotNull PsiPackage aPackage) { + if (!aPackage.getQualifiedName().isEmpty()) { + processor = new DelegatingScopeProcessor(processor) { + @Nullable + @Override + public T getHint(@NotNull Key hintKey) { + if (hintKey == ElementClassHint.KEY) { + //noinspection unchecked + return (T)new ElementClassHint() { + @Override + public boolean shouldProcess(DeclarationKind kind) { + return kind == DeclarationKind.CLASS; + } + }; + } + return super.getHint(hintKey); + } + }; + } + return aPackage.processDeclarations(processor, state, null, place); + } + @NotNull private static PsiSubstitutor createRawSubstitutor(PsiClass containingClass) { return JavaPsiFacade.getElementFactory(containingClass.getProject()).createRawSubstitutor(containingClass); @@ -421,7 +439,7 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava private static boolean processOnDemandTarget(PsiElement target, PsiScopeProcessor processor, ResolveState substitutor, PsiElement place) { if (target instanceof PsiPackage) { - if (!target.processDeclarations(processor, substitutor, null, place)) { + if (!processPackageDeclarations(processor, substitutor, place, (PsiPackage)target)) { return false; } } @@ -436,7 +454,7 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava } } else { - LOG.assertTrue(false); + LOG.error(target); } return true; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index 79b1c1151bbb..8112b4d60872 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source.resolve.graphInference.constraints; +import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable; @@ -51,7 +52,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm final PsiType type = myExpression.getType(); session.registerIncompatibleErrorMessage((type != null ? type.getPresentableText() : myExpression.getText()) + " is not compatible with " + session.getPresentableText(myT)); } - else if (TypeCompatibilityConstraint.isUncheckedConversion(myT, exprType)) { + else if (TypeCompatibilityConstraint.isUncheckedConversion(myT, exprType) && !JavaGenericsUtil.isReifiableType(myT)) { session.setErasedDuringApplicabilityCheck(); } return assignmentCompatible; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedConversionDuringProperTypeExpressionConstraintResolution.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedConversionDuringProperTypeExpressionConstraintResolution.java index 4d85bb7bce2a..4382aeba2e9e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedConversionDuringProperTypeExpressionConstraintResolution.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedConversionDuringProperTypeExpressionConstraintResolution.java @@ -1,3 +1,4 @@ +import java.util.function.Consumer; class Test { private static AG foo(Class clz) { return (AG) foo1(clz); @@ -15,3 +16,39 @@ class Test { } +class Test1 { + + static class D { + public D(Consumer c, Class cl) { + } + + static D create(Consumer c, Class ck) { + return new D<>(c, ck); + } + } + + { + Class c = D.class; + + D d = new D<>(s -> s.isEmpty(), c); + D d1 = D.create(s -> s.isEmpty(), c); + } +} +class Test2 { + + static class D { + public D(Consumer c, Class cl) { + } + + static D create(Consumer c, Class ck) { + return new D<>(c, ck); + } + } + + { + Class c = D.class; + + D d = new D<>(s -> s.isEmpty(), c); + D d1 = D.create(s -> s.isEmpty(), c); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterNoParamsQualifier.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterNoParamsQualifier.java index e83bebc07b4a..a8093e9a0c85 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterNoParamsQualifier.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterNoParamsQualifier.java @@ -1,4 +1,4 @@ -// "Replace lambda with method reference" "true" +// "Replace lambda with method reference (may change semantics)" "true" class Example { public void m() { } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterPureMethodCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterPureMethodCall.java index ea47af04af5e..b5f548130701 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterPureMethodCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterPureMethodCall.java @@ -1,4 +1,4 @@ -// "Replace lambda with method reference" "true" +// "Replace lambda with method reference (may change semantics)" "true" import java.util.*; import java.util.function.Predicate; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeNoParamsQualifier.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeNoParamsQualifier.java index ef76c76554ee..9fd8323f03eb 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeNoParamsQualifier.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeNoParamsQualifier.java @@ -1,4 +1,4 @@ -// "Replace lambda with method reference" "true" +// "Replace lambda with method reference (may change semantics)" "true" class Example { public void m() { } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforePureMethodCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforePureMethodCall.java index e17924ba9713..fac7bb1c2d05 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforePureMethodCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforePureMethodCall.java @@ -1,4 +1,4 @@ -// "Replace lambda with method reference" "true" +// "Replace lambda with method reference (may change semantics)" "true" import java.util.*; import java.util.function.Predicate; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAnnotationInverted.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAnnotationInverted.java new file mode 100644 index 000000000000..4fed8347f15e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAnnotationInverted.java @@ -0,0 +1,15 @@ +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.util.Optional; + +public class Main { + public static Optional findAnnotation(Optional element) { + return element.>map(annotatedElement -> Optional.empty()).orElseGet(() -> findAnnotation((AnnotatedElement) null)); + } + + private static Optional findAnnotation(AnnotatedElement element) { + return Optional.empty(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java index a097e38e57e1..d1565ef90a3a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java @@ -3,13 +3,14 @@ import java.util.*; public class Main { - public void testOptional(Optional str) { - String val; - // line comment -// another line comment -//before trim -/* block comment *//*block comment*/ - val = str.map(String::trim).orElse(""); - System.out.println(val); - } + public void testOptional(Optional str) { + String val; + // line comment + // another line comment + /* block comment */ + /*block comment*/ + //before trim + val = str.map(String::trim).orElse(""); + System.out.println(val); + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java index fba7408b5a4e..b25e341e57cc 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with functional style expression" "true" +// "Replace Optional.isPresent() condition with functional style expression" "GENERIC_ERROR_OR_WARNING" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerNestedIf.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerNestedIf.java new file mode 100644 index 000000000000..7887a72881d0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerNestedIf.java @@ -0,0 +1,12 @@ +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" + +import java.util.Optional; + +public class Main { + public void test(Optional opt) { + opt.ifPresent(s -> { + if (s.equals("abc")) + System.out.println(s); + }); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerTwoStatements.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerTwoStatements.java new file mode 100644 index 000000000000..b63c5938df8c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerTwoStatements.java @@ -0,0 +1,13 @@ +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" + +import java.util.*; + +public class Main { + public void testOptional(Optional str) { + str.ifPresent(s -> { + System.out.println(s); + // once again! + System.out.println(s); + }); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java index 07ee230d09cd..1a664ad0350d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java @@ -11,7 +11,10 @@ public class Main { } public Number testOptionalComments(Optional strList) { - /* optional is present *//*return something *//*too big*//* optional is absent *//* return null*/ - return strList.map(myList -> myList.size() > 1 ? myList.get(1) : 1.0).orElse(null); + /* optional is present */ + /*return something */ + /* optional is absent */ + /* return null*/ + return strList.map(myList -> myList.size() > /*too big*/ 1 ? myList.get(1) : 1.0).orElse(null); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAnnotationInverted.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAnnotationInverted.java index 2b8fadbd3cde..51d83a5dd283 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAnnotationInverted.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAnnotationInverted.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with functional style expression" "false" +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java index b22119c8d5ec..a303b52c9d6d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java @@ -3,16 +3,16 @@ import java.util.*; public class Main { - public void testOptional(Optional str) { - String val; - if (str.isPresent()) { - val = // line comment - // another line comment - str.get()//before trim - .trim() /* block comment *//*block comment*/; - } else { - val = ""; + public void testOptional(Optional str) { + String val; + if (str.isPresent()) { + val = // line comment + // another line comment + str.get()//before trim + .trim() /* block comment *//*block comment*/; + } else { + val = ""; + } + System.out.println(val); } - System.out.println(val); - } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java index c8bd21c05e06..aa493a049e19 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with functional style expression" "true" +// "Replace Optional.isPresent() condition with functional style expression" "GENERIC_ERROR_OR_WARNING" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerNestedIf.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerNestedIf.java new file mode 100644 index 000000000000..e147d990743c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerNestedIf.java @@ -0,0 +1,12 @@ +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" + +import java.util.Optional; + +public class Main { + public void test(Optional opt) { + if(opt.isPresent()) { + if(opt.get().equals("abc")) + System.out.println(opt.get()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java index e62b7210bfee..2c5766ed79b8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with functional style expression" "false" +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" import java.util.*; @@ -6,6 +6,7 @@ public class Main { public void testOptional(Optional str) { if (str.isPresent()) { System.out.println(str.get()); + // once again! System.out.println(str.get()); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterFewParameters.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterFewParameters.java index 868cf5e74f5c..41be36ab87bc 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterFewParameters.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterFewParameters.java @@ -1,4 +1,4 @@ -// "Wrap 4th parameter using 'Arrays.asList'" "true" +// "Wrap 4th parameter using 'Arrays.asList()'" "true" import java.util.Arrays; import java.util.List; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterSingleParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterSingleParameter.java index 9544df9a4c52..12514e409eb2 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterSingleParameter.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterSingleParameter.java @@ -1,4 +1,4 @@ -// "Wrap using 'Arrays.asList'" "true" +// "Wrap using 'Arrays.asList()'" "true" import java.util.Arrays; import java.util.List; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeFewParameters.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeFewParameters.java index 92ed4293c63b..6538e52c7a1a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeFewParameters.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeFewParameters.java @@ -1,4 +1,4 @@ -// "Wrap 4th parameter using 'Arrays.asList'" "true" +// "Wrap 4th parameter using 'Arrays.asList()'" "true" import java.util.List; public class Test { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible.java index 8a8e0153aed4..4090aae07fe8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible.java @@ -1,4 +1,4 @@ -// "Wrap using 'Arrays.asList'" "false" +// "Wrap using 'Arrays.asList()'" "false" import java.util.LinkedList; public class Test { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible2.java index c27ca44463db..8ac304049dcf 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible2.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible2.java @@ -1,4 +1,4 @@ -// "Wrap using 'Arrays.asList'" "false" +// "Wrap using 'Arrays.asList()'" "false" import java.util.LinkedList; public class Test { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeSingleParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeSingleParameter.java index a29aaa36c86d..70aa10c065d2 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeSingleParameter.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeSingleParameter.java @@ -1,4 +1,4 @@ -// "Wrap using 'Arrays.asList'" "true" +// "Wrap using 'Arrays.asList()'" "true" import java.util.List; public class Test { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseAssignment.java index ea20b8721e18..0a14af950feb 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseAssignment.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseAssignment.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { private long lo = Long.parseLong("42"); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInCall.java index 5ce32b3862cb..a98cbeaf2fc1 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { void ba() { fa(Long.parseLong("42")); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInVarargsCall.java index 31706139c373..686660bc26be 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { void ba(long l) { fa(l, Long.parseLong("42")); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofAssignment.java index 1ac02ad800e2..80f3fc0f8f3a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofAssignment.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofAssignment.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { private Long lo = Long.valueOf("42"); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofCall.java index 19333acdf670..b0eeadc9d417 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba() { fa(Long.valueOf("42")); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofInVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofInVarargsCall.java index 11e61b1c5d59..2c1aee72c86c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofInVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofInVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba(Long l) { fa(l, Long.valueOf("42")); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofVarargsCall.java index 4291e43fe0a1..13cf7d09d885 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba() { fa(Long.valueOf("42")); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseAssignment.java index 0700d003d994..cb594414444f 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseAssignment.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseAssignment.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { private long lo = "42"; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInCall.java index d4d0283e1f6c..2535e8ed769d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { void ba() { fa("42"); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInVarargsCall.java index 62ca613e69d9..364221f6c461 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { void ba(long l) { fa(l, "42"); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofAssignment.java index 8b812118de12..36b4c9c596f0 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofAssignment.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofAssignment.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { private Long lo = "42"; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofCall.java index 17604b21f05c..04a28c62cc92 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba() { fa("42"); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofInVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofInVarargsCall.java index a49a329bbf79..fb52654805b8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofInVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofInVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba(Long l) { fa(l, "42"); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofVarargsCall.java index 7dd6f914ff0a..c82e585b9a0d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba() { fa("42"); diff --git a/java/java-tests/testData/psi/resolve/class/NoSubpackagesAccess.java b/java/java-tests/testData/psi/resolve/class/NoSubpackagesAccess.java new file mode 100644 index 000000000000..d8d09972b64a --- /dev/null +++ b/java/java-tests/testData/psi/resolve/class/NoSubpackagesAccess.java @@ -0,0 +1,8 @@ +import javax.*; + +class Foo { + { + foo.bar.goo d; + } +} + diff --git a/java/java-tests/testSrc/com/intellij/index/StringIndex.java b/java/java-tests/testSrc/com/intellij/index/StringIndex.java index b5e2603eb09e..379a0e2ae236 100644 --- a/java/java-tests/testSrc/com/intellij/index/StringIndex.java +++ b/java/java-tests/testSrc/com/intellij/index/StringIndex.java @@ -15,6 +15,7 @@ */ package com.intellij.index; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.*; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.EnumeratorStringDescriptor; @@ -75,7 +76,7 @@ public class StringIndex { } public List getFilesByWord(@NotNull String word) throws StorageException { - return myIndex.getData(word).toValueList(); + return ContainerUtil.collect(myIndex.getData(word).getValueIterator()); } public void update(final String path, @Nullable String content, @Nullable String oldContent) throws StorageException { diff --git a/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java b/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java index 81ef00ffdbbb..36637e540dbd 100644 --- a/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java @@ -17,6 +17,7 @@ package com.intellij.psi.resolve; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; @@ -31,8 +32,14 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.ResolveTestCase; +import com.intellij.util.containers.ContainerUtil; +import org.easymock.IArgumentMatcher; +import java.lang.reflect.Method; import java.util.Collections; +import java.util.Set; + +import static org.easymock.EasyMock.*; public class ResolveClassTest extends ResolveTestCase { public void testFQName() throws Exception { @@ -268,4 +275,41 @@ public class ResolveClassTest extends ResolveTestCase { private PsiReference configure() throws Exception { return configureByFile("class/" + getTestName(false) + ".java"); } + + public void testNoSubpackagesAccess() throws Exception { + PsiElementFinder mock = createMockFinder(); + PlatformTestUtil.registerExtension(Extensions.getArea(getProject()), PsiElementFinder.EP_NAME, mock, getTestRootDisposable()); + + PsiReference reference = configure(); + assertNull(reference.resolve()); + reference.getVariants(); + + verify(mock); + } + + private static PsiElementFinder createMockFinder() { + Set ignoredMethods = ContainerUtil.newHashSet("getClassesFilter", "processPackageDirectories", "getClasses"); + Method[] methods = ContainerUtil.findAllAsArray(PsiElementFinder.class.getDeclaredMethods(), m -> !ignoredMethods.contains(m.getName())); + PsiElementFinder mock = createMockBuilder(PsiElementFinder.class).addMockedMethods(methods).createMock(); + expect(mock.findClasses(anyObject(), anyObject())).andReturn(PsiClass.EMPTY_ARRAY).anyTimes(); + expect(mock.findPackage(eq("foo"))).andReturn(null); + expect(mock.getSubPackages(rootPackage(), anyObject())).andReturn(PsiPackage.EMPTY_ARRAY); + replay(mock); + return mock; + } + + private static PsiPackage rootPackage() { + reportMatcher(new IArgumentMatcher() { + @Override + public boolean matches(Object argument) { + return "PsiPackage:".equals(String.valueOf(argument)); + } + + @Override + public void appendTo(StringBuffer buffer) { + buffer.append("PsiPackage:"); + } + }); + return null; + } } diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/ActionHint.java b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/ActionHint.java index 425a6558ba4e..897d79453bd4 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/ActionHint.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/ActionHint.java @@ -16,6 +16,8 @@ package com.intellij.codeInsight.daemon.quickFix; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.codeInspection.ex.QuickFixWrapper; import com.intellij.lang.Commenter; import com.intellij.lang.LanguageCommenters; import com.intellij.lang.injection.InjectedLanguageManager; @@ -40,10 +42,12 @@ import static org.junit.Assert.fail; public class ActionHint { final String myExpectedText; final boolean myShouldPresent; + final ProblemHighlightType myHighlightType; - private ActionHint(String expectedText, boolean shouldPresent) { + private ActionHint(String expectedText, boolean shouldPresent, ProblemHighlightType severity) { myExpectedText = expectedText; myShouldPresent = shouldPresent; + myHighlightType = severity; } /** @@ -79,11 +83,25 @@ public class ActionHint { @Nullable public IntentionAction findAndCheck(Collection actions, Supplier infoSupplier) { IntentionAction result = actions.stream().filter(t -> t.getText().equals(myExpectedText)).findFirst().orElse(null); - if(result == null && myShouldPresent) { - fail("Action with text '" + myExpectedText + "' not found\nAvailable actions: " + - actions.stream().map(IntentionAction::getText).collect(Collectors.joining(", ", "[", "]\n")) + - infoSupplier.get()); - } else if(result != null && !myShouldPresent) { + if(myShouldPresent) { + if(result == null) { + fail("Action with text '" + myExpectedText + "' not found\nAvailable actions: " + + actions.stream().map(IntentionAction::getText).collect(Collectors.joining(", ", "[", "]\n")) + + infoSupplier.get()); + } else if(myHighlightType != null) { + if(!(result instanceof QuickFixWrapper)) { + fail("Action with text '" + myExpectedText + "' is not a LocalQuickFix, but " + result.getClass().getName() + + "\nExpected LocalQuickFix with ProblemHighlightType=" + myHighlightType + "\n" + + infoSupplier.get()); + } + ProblemHighlightType actualType = ((QuickFixWrapper)result).getHighlightType(); + if(actualType != myHighlightType) { + fail("Action with text '" + myExpectedText + "' has wrong ProblemHighlightType.\nExpected: " + myHighlightType + + "\nActual: " + actualType + "\n" + infoSupplier.get()); + } + } + } + else if(result != null) { fail("Action with text '" + myExpectedText + "' is present, but should not\n" + infoSupplier.get()); } return result; @@ -93,8 +111,13 @@ public class ActionHint { * Parse given file with given contents extracting ActionHint of it. *

* Currently the following syntax is supported: - * // "quick-fix name or intention text" "true|false" - * (replace // with line comment prefix in the corresponding language if necessary) + *

+ * {@code // "quick-fix name or intention text" "true|false|"} + *

+ * (replace // with line comment prefix in the corresponding language if necessary). + * If {@link ProblemHighlightType} enum value is specified instead of true/false + * (e.g. {@code "INFORMATION"}), then + * it's expected that the action is present and it's a quick-fix with given highlight type. *

* * @param file PsiFile associated with contents (used to determine the language) @@ -114,11 +137,15 @@ public class ActionHint { assert comment != null : commenter; // "quick fix action text to perform" "should be available" - Pattern pattern = Pattern.compile("^" + Pattern.quote(comment) + " \"(.*)\" \"(true|false)\".*", Pattern.DOTALL); + Pattern pattern = Pattern.compile("^" + Pattern.quote(comment) + " \"(.*)\" \"(\\w+)\".*", Pattern.DOTALL); Matcher matcher = pattern.matcher(contents); TestCase.assertTrue("No comment found in " + file.getVirtualFile(), matcher.matches()); final String text = matcher.group(1); - final boolean actionShouldBeAvailable = Boolean.parseBoolean(matcher.group(2)); - return new ActionHint(text, actionShouldBeAvailable); + String state = matcher.group(2); + if(state.equals("true") || state.equals("false")) { + return new ActionHint(text, Boolean.parseBoolean(state), null); + } else { + return new ActionHint(text, true, ProblemHighlightType.valueOf(state)); + } } } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java index 5c6d17c4c560..13e15b3b801d 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -20,6 +20,7 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.QuickFix; import com.intellij.openapi.command.undo.UndoUtil; import com.intellij.openapi.diagnostic.Logger; @@ -29,6 +30,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; /** * @author max @@ -104,6 +106,11 @@ public class QuickFixWrapper implements IntentionAction { return (LocalQuickFix)myDescriptor.getFixes()[myFixNumber]; } + @TestOnly + public ProblemHighlightType getHighlightType() { + return myDescriptor.getHighlightType(); + } + public String toString() { return getText(); } diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LibraryLicensesListGenerator.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LibraryLicensesListGenerator.groovy index 338fb4c66444..d7e83f97a289 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LibraryLicensesListGenerator.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LibraryLicensesListGenerator.groovy @@ -85,7 +85,7 @@ class LibraryLicensesListGenerator { LibraryLicense lib = it.key String moduleName = it.value def name = lib.url != null ? "[$lib.name|$lib.url]" : lib.name - def license = lib.libraryLicenseUrl != null ? "[$lib.license|$lib.licenseUrl]" : lib.license + def license = lib.libraryLicenseUrl != null ? "[$lib.license|$lib.libraryLicenseUrl]" : lib.license projectBuilder.info(" $lib.name (in module $moduleName)") lines << "|$name| ${lib.version ?: ""}|$license|".toString() } diff --git a/platform/configuration-store-impl/src/ProjectStoreImpl.kt b/platform/configuration-store-impl/src/ProjectStoreImpl.kt index 227f124482b9..0248817ce07e 100644 --- a/platform/configuration-store-impl/src/ProjectStoreImpl.kt +++ b/platform/configuration-store-impl/src/ProjectStoreImpl.kt @@ -31,6 +31,7 @@ import com.intellij.openapi.diagnostic.catchAndLog import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.Project +import com.intellij.openapi.project.ProjectCoreUtil import com.intellij.openapi.project.impl.ProjectImpl import com.intellij.openapi.project.impl.ProjectManagerImpl.UnableToSaveProjectNotification import com.intellij.openapi.project.impl.ProjectStoreClassProvider @@ -255,7 +256,7 @@ abstract class ProjectStoreBase(override final val project: ProjectImpl) : Compo } override fun isProjectFile(file: VirtualFile): Boolean { - if (!file.isInLocalFileSystem) { + if (!file.isInLocalFileSystem || !ProjectCoreUtil.isProjectOrWorkspaceFile(file, file.fileType)) { return false } diff --git a/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java b/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java index be3fd5f63435..38e7384b0e5c 100644 --- a/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java +++ b/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java @@ -213,7 +213,8 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements P } public final boolean isCustomFoldingCandidate(@NotNull PsiElement element) { - return isCustomFoldingCandidate(element.getNode()); + ASTNode node = element.getNode(); + return node != null && isCustomFoldingCandidate(node); } /** diff --git a/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.java b/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.java index 38321417c29e..b3e29e6b19b3 100644 --- a/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.java +++ b/platform/indexing-impl/src/com/intellij/util/indexing/ScalarIndexExtension.java @@ -17,12 +17,8 @@ package com.intellij.util.indexing; import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.VoidDataExternalizer; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; /** * A specialization of FileBasedIndexExtension allowing to create a mapping [DataObject -> List of files containing this object] @@ -30,24 +26,15 @@ import java.io.IOException; */ public abstract class ScalarIndexExtension extends FileBasedIndexExtension{ - public static final DataExternalizer VOID_DATA_EXTERNALIZER = new VoidDataExternalizer(); + /** + * To remove in IDEA 2018.1. Use {@link VoidDataExternalizer.INSTANCE} + */ + @Deprecated + public static final DataExternalizer VOID_DATA_EXTERNALIZER = VoidDataExternalizer.INSTANCE; @NotNull @Override public final DataExternalizer getValueExternalizer() { - return VOID_DATA_EXTERNALIZER; - } - - private static class VoidDataExternalizer implements DataExternalizer { - - @Override - public void save(@NotNull final DataOutput out, final Void value) throws IOException { - } - - @Override - @Nullable - public Void read(@NotNull final DataInput in) throws IOException { - return null; - } + return VoidDataExternalizer.INSTANCE; } } \ No newline at end of file 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 f3cd34b1f9e2..418c73b0d6e7 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -66,7 +66,6 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; -import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.search.GlobalSearchScope; @@ -420,13 +419,11 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } private void addFlushRequest(@NotNull MyFlushRunnable flushRunnable, final int millis) { - StartupManager.getInstance(myProject).runWhenProjectIsInitialized(() -> { - synchronized (myCurrentRequests) { - if (!myFlushAlarm.isDisposed() && myCurrentRequests.add(flushRunnable)) { - myFlushAlarm.addRequest(flushRunnable, millis, getStateForUpdate()); - } + synchronized (myCurrentRequests) { + if (!myFlushAlarm.isDisposed() && myCurrentRequests.add(flushRunnable)) { + myFlushAlarm.addRequest(flushRunnable, millis, getStateForUpdate()); } - }); + } } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 1fe1a3a4f0cb..fd8b7230f93e 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -373,13 +373,14 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA return; } String text = ""; - //if (myEditor != null) { - // text = myEditor.getSelectionModel().getSelectedText(); - // text = text == null ? "" : text.trim(); - //} + if (myEditor != null) { + text = myEditor.getSelectionModel().getSelectedText(); + text = text == null ? "" : text.trim(); + } search.setText(text); search.getTextEditor().setForeground(UIUtil.getLabelForeground()); + search.selectText(); //titleIndex = new TitleIndexes(); editor.setColumns(SEARCH_FIELD_COLUMNS); myFocusComponent = e.getOppositeComponent(); diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index b71a4a021d3d..1bfab88edf95 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -52,7 +52,6 @@ import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.*; -import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; @@ -139,7 +138,6 @@ public abstract class ChooseByNameBase { private final ListUpdater myListUpdater = new ListUpdater(); private boolean myDisposedFlag = false; - private ActionCallback myPostponedOkAction; private final String[][] myNames = new String[2][]; private volatile CalcElementsThread myCalcElementsThread; @@ -163,15 +161,10 @@ public abstract class ChooseByNameBase { private ShortcutSet myCheckBoxShortcut; protected boolean myInitIsDone; static final boolean ourLoadNamesEachTime = FileBasedIndex.ourEnableTracingOfKeyHashToVirtualFileMapping; - private boolean myFixLostTyping = true; private boolean myAlwaysHasMore = false; private Point myFocusPoint; public boolean checkDisposed() { - if (myDisposedFlag && myPostponedOkAction != null && !myPostponedOkAction.isProcessed()) { - myPostponedOkAction.setRejected(); - } - return myDisposedFlag; } @@ -569,7 +562,6 @@ public abstract class ChooseByNameBase { myTextField.getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { - clearPostponedOkAction(false); rebuildList(false); } }); @@ -777,12 +769,10 @@ public abstract class ChooseByNameBase { if (checkDisposed()) return; if (closeForbidden(ok)) return; - if (postponeCloseWhenListReady(ok)) return; cancelListUpdater(); close(ok); - clearPostponedOkAction(ok); myListModel.removeAll(); } @@ -797,36 +787,15 @@ public abstract class ChooseByNameBase { final CalcElementsThread calcElementsThread = myCalcElementsThread; if (calcElementsThread != null) { calcElementsThread.cancel(); - backgroundCalculationFinished(Collections.emptyList(), 0); + myCalcElementsThread = null; } myListUpdater.cancelAll(); } - private boolean postponeCloseWhenListReady(boolean ok) { - if (!isToFixLostTyping()) return false; - - final String text = getTrimmedText(); - if (ok && myCalcElementsThread != null && !text.isEmpty()) { - myPostponedOkAction = new ActionCallback(); - IdeFocusManager.getInstance(myProject).typeAheadUntil(myPostponedOkAction); - return true; - } - - return false; - } - @NotNull public String getTrimmedText() { return StringUtil.trimLeading(StringUtil.notNullize(myTextField.getText())); } - public void setFixLostTyping(boolean fixLostTyping) { - myFixLostTyping = fixLostTyping; - } - - protected boolean isToFixLostTyping() { - return myFixLostTyping && Registry.is("actionSystem.fixLostTyping"); - } - @NotNull private synchronized String[] ensureNamesLoaded(boolean checkboxState) { String[] cached = getNamesSync(checkboxState); @@ -1038,7 +1007,6 @@ public abstract class ChooseByNameBase { myTextField.setForeground(JBColor.red); myListUpdater.cancelAll(); hideList(); - clearPostponedOkAction(false); return; } @@ -1046,7 +1014,6 @@ public abstract class ChooseByNameBase { Object[] newElements = elements.toArray(); List commands = ModelDiff.createDiffCmds(myListModel, oldElements, newElements); if (commands == null) { - myListUpdater.doPostponedOkIfNeeded(); return; // Nothing changed } @@ -1168,9 +1135,6 @@ public abstract class ChooseByNameBase { if (!myCommands.isEmpty()) { myAlarm.addRequest(this, DELAY); } - else { - doPostponedOkIfNeeded(); - } if (!checkDisposed()) { showList(); myTextFieldPanel.repositionHint(); @@ -1184,31 +1148,11 @@ public abstract class ChooseByNameBase { }, DELAY); } - private void doPostponedOkIfNeeded() { - if (myPostponedOkAction != null) { - if (getChosenElement() != null) { - doClose(true); - } - clearPostponedOkAction(checkDisposed()); - } - } - } - - private void clearPostponedOkAction(boolean success) { - if (myPostponedOkAction != null) { - if (success) { - myPostponedOkAction.setDone(); - } - else { - myPostponedOkAction.setRejected(); - } - } - - myPostponedOkAction = null; } + @Deprecated public boolean hasPostponedAction() { - return myPostponedOkAction != null; + return false; } protected abstract void showList(); @@ -1646,10 +1590,6 @@ public abstract class ChooseByNameBase { myListSizeIncreasing = listSizeIncreasing; } - public boolean isAlwaysHasMore() { - return myAlwaysHasMore; - } - /** * Display ... item at the end of the list regardless of whether it was filled up or not. * This option can be useful in cases, when it can't be said beforehand, that the next call to {@link ChooseByNameItemProvider} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java index 616329635949..68dace008537 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java @@ -24,9 +24,7 @@ import com.intellij.codeInsight.hint.HintUtil; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ex.*; import com.intellij.icons.AllIcons; -import com.intellij.ide.CommonActionsManager; -import com.intellij.ide.DefaultTreeExpander; -import com.intellij.ide.TreeExpander; +import com.intellij.ide.*; import com.intellij.ide.ui.search.SearchUtil; import com.intellij.ide.ui.search.SearchableOptionsRegistrar; import com.intellij.lang.annotation.HighlightSeverity; @@ -36,6 +34,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.options.ex.Settings; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; @@ -71,10 +70,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.TreeExpansionEvent; -import javax.swing.event.TreeExpansionListener; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; +import javax.swing.event.*; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; @@ -93,6 +89,7 @@ public class SingleInspectionProfilePanel extends JPanel { @NonNls private static final String EMPTY_HTML = ""; private static final float DIVIDER_PROPORTION_DEFAULT = 0.5f; + public static final String SETTINGS = "settings://"; private final Map myInitialToolDescriptors = new THashMap<>(); private final InspectionConfigTreeNode myRoot = @@ -1041,7 +1038,25 @@ public class SingleInspectionProfilePanel extends JPanel { myBrowser = new JEditorPane(UIUtil.HTML_MIME, EMPTY_HTML); myBrowser.setEditable(false); myBrowser.setBorder(IdeBorderFactory.createEmptyBorder(5, 5, 5, 5)); - myBrowser.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE); + myBrowser.addHyperlinkListener(new HyperlinkAdapter() { + @Override + protected void hyperlinkActivated(HyperlinkEvent e) { + String description = e.getDescription(); + if (description.startsWith(SETTINGS)) { + String configId = description.substring(SETTINGS.length()); + DataContext context = DataManager.getInstance().getDataContextFromFocus().getResult(); + if (context != null) { + Settings settings = Settings.KEY.getData(context); + if (settings != null) { + settings.select(settings.find(configId)); + } + } + } + else { + BrowserUtil.browse(description); + } + } + }); initToolStates(); fillTreeData(myProfileFilter != null ? myProfileFilter.getFilter() : null, true); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java index 467ba0cf3202..6679a10040ab 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java @@ -26,7 +26,6 @@ import org.jetbrains.annotations.Nullable; import java.io.DataOutput; import java.io.IOException; -import java.util.List; /** * @author Eugene Zhuravlev @@ -82,24 +81,6 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer return getMergedData().getValueIterator(); } - @NotNull - @Override - public List toValueList() { - return getMergedData().toValueList(); - } - - @NotNull - @Override - public IntPredicate getValueAssociationPredicate(Value value) { - return getMergedData().getValueAssociationPredicate(value); - } - - @NotNull - @Override - public IntIterator getInputIdsIterator(final Value value) { - return getMergedData().getInputIdsIterator(value); - } - public void dropMergedData() { myMerged = null; } @@ -164,7 +145,7 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer } }); } - setNeedsCompacting(fromDisk.needsCompacting()); + setNeedsCompacting(((UpdatableValueContainer)fromDisk).needsCompacting()); myMerged = newMerged; return newMerged; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 86afd87c55aa..7f770c9c17b6 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -914,9 +914,9 @@ public class FileBasedIndexImpl extends FileBasedIndex { @NotNull K dataKey, @Nullable VirtualFile restrictToFile, @NotNull GlobalSearchScope scope, - @NotNull Processor> valueProcessor) { + @NotNull Processor> valueProcessor) { final Boolean result = processExceptions(indexId, restrictToFile, scope, - index -> valueProcessor.process(index.getData(dataKey).getValueIterator())); + index -> valueProcessor.process((ValueIteratorImpl)index.getData(dataKey).getValueIterator())); return result == null || result.booleanValue(); } @@ -1053,10 +1053,10 @@ public class FileBasedIndexImpl extends FileBasedIndex { } @Nullable - private static TIntHashSet collectInputIdsContainingAllKeys(@NotNull UpdatableIndex index, + private static TIntHashSet collectInputIdsContainingAllKeys(@NotNull InvertedIndex index, @NotNull Collection dataKeys, @Nullable Condition valueChecker, - @Nullable ValueContainer.IntPredicate idChecker) + @Nullable IntPredicate idChecker) throws StorageException { TIntHashSet mainIntersection = null; @@ -1065,7 +1065,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { final TIntHashSet copy = new TIntHashSet(); final ValueContainer container = index.getData(dataKey); - for (final ValueContainer.ValueIterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { + for (ValueIteratorImpl valueIt = (ValueIteratorImpl)container.getValueIterator(); valueIt.hasNext(); ) { final V value = valueIt.next(); if (valueChecker != null && !valueChecker.value(value)) { continue; @@ -1085,7 +1085,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { } else { mainIntersection.forEach(new TIntProcedure() { - final ValueContainer.IntPredicate predicate = valueIt.getValueAssociationPredicate(); + final IntPredicate predicate = valueIt.getValueAssociationPredicate(); @Override public boolean execute(int id) { @@ -1107,7 +1107,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { @NotNull - public static ValueContainer.IntIterator collectInputIdsContainingAllKeys(@NotNull UpdatableIndex index, + public static ValueContainer.IntIterator collectInputIdsContainingAllKeys(@NotNull InvertedIndex index, @NotNull Collection dataKeys) throws StorageException { TIntHashSet result = collectInputIdsContainingAllKeys(index, dataKeys, null, null); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileId2ValueMapping.java b/platform/lang-impl/src/com/intellij/util/indexing/FileId2ValueMapping.java index 5a6b3357bc99..48f5e6127a0f 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileId2ValueMapping.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileId2ValueMapping.java @@ -73,7 +73,7 @@ class FileId2ValueMapping { valueContainer.removeValue(inputId, mapped); } if (DebugAssertions.EXTRA_SANITY_CHECKS && myOnePerFileValidationEnabled) { - for (final ValueContainer.ValueIterator valueIterator = valueContainer.getValueIterator(); valueIterator.hasNext();) { + for (final ValueIteratorImpl valueIterator = valueContainer.getValueIterator(); valueIterator.hasNext();) { valueIterator.next(); DebugAssertions.assertTrue(!valueIterator.getValueAssociationPredicate().contains(inputId)); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IntPredicate.java b/platform/lang-impl/src/com/intellij/util/indexing/IntPredicate.java new file mode 100644 index 000000000000..a0d2e86bcc35 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/IntPredicate.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util.indexing; + +/** + * Created by Maxim.Mossienko on 11/22/2016. + */ +public interface IntPredicate { + boolean contains(int id); +} diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java index 3d8c5fb15d9b..2a8da9085bc9 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java @@ -16,8 +16,9 @@ package com.intellij.util.indexing; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,25 +28,15 @@ import java.util.concurrent.locks.Lock; * @author Eugene Zhuravlev * Date: Dec 10, 2007 */ -public interface UpdatableIndex extends AbstractIndex { +public interface UpdatableIndex extends InvertedIndex { - void clear() throws StorageException; - - void flush() throws StorageException; - - /** - * @param inputId *positive* id of content. - */ - @NotNull - Computable update(int inputId, @Nullable Input content); + boolean processAllKeys(@NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; @NotNull Lock getReadLock(); @NotNull Lock getWriteLock(); - - void dispose(); void setIndexedStateForFile(int fileId, @NotNull VirtualFile file); void resetIndexedStateForFile(int fileId); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableValueContainer.java index 789e9c18bc8e..9b5770ec0c71 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableValueContainer.java @@ -25,4 +25,14 @@ public abstract class UpdatableValueContainer extends ValueContainer{ public abstract void addValue(int inputId, T value); public abstract void removeAssociatedValue(int inputId); + + private volatile boolean myNeedsCompacting; + + boolean needsCompacting() { + return myNeedsCompacting; + } + + void setNeedsCompacting(boolean value) { + myNeedsCompacting = value; + } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java index 591a4a0d5b6e..d39fa1f150bb 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java @@ -31,8 +31,6 @@ import org.jetbrains.annotations.Nullable; import java.io.DataInputStream; import java.io.DataOutput; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -86,7 +84,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement if (myInputIdMapping == null) return; List fileSetObjects = null; List valueObjects = null; - for (final ValueIterator valueIterator = getValueIterator(); valueIterator.hasNext();) { + for (final ValueIteratorImpl valueIterator = getValueIterator(); valueIterator.hasNext();) { final Value value = valueIterator.next(); if (valueIterator.getValueAssociationPredicate().contains(inputId)) { @@ -144,10 +142,10 @@ class ValueContainerImpl extends UpdatableValueContainer implement @NotNull @Override - public ValueIterator getValueIterator() { + public ValueIteratorImpl getValueIterator() { if (myInputIdMapping != null) { if (!(myInputIdMapping instanceof THashMap)) { - return new ValueIterator() { + return new ValueIteratorImpl() { private Value value = (Value)myInputIdMapping; @NotNull @@ -186,7 +184,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement } }; } else { - return new ValueIterator() { + return new ValueIteratorImpl() { private Value current; private Object currentValue; private final THashMap myMapping = ((THashMap)myInputIdMapping); @@ -235,7 +233,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement } } - static class EmptyValueIterator extends EmptyIterator implements ValueIterator { + static class EmptyValueIterator extends EmptyIterator implements ValueIteratorImpl { @NotNull @Override @@ -257,24 +255,6 @@ class ValueContainerImpl extends UpdatableValueContainer implement private static final EmptyValueIterator emptyIterator = new EmptyValueIterator(); - @NotNull - @Override - public List toValueList() { - if (myInputIdMapping == null) { - return Collections.emptyList(); - } else if (myInputIdMapping instanceof THashMap) { - return new ArrayList<>(((THashMap)myInputIdMapping).keySet()); - } else { - return new SmartList<>((Value)myInputIdMapping); - } - } - - @NotNull - @Override - public IntPredicate getValueAssociationPredicate(Value value) { - return getPredicateOutOfFileSetObject(getFileSetObject(value)); - } - private static @NotNull IntPredicate getPredicateOutOfFileSetObject(@Nullable Object input) { if (input == null) return EMPTY_PREDICATE; @@ -291,12 +271,6 @@ class ValueContainerImpl extends UpdatableValueContainer implement return ((ChangeBufferingList)input).intPredicate(); } - @NotNull - @Override - public IntIterator getInputIdsIterator(Value value) { - return getIntIteratorOutOfFileSetObject(getFileSetObject(value)); - } - private static @NotNull IntIterator getIntIteratorOutOfFileSetObject(@Nullable Object input) { if (input == null) return EMPTY_ITERATOR; if (input instanceof Integer){ @@ -436,7 +410,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement public void saveTo(DataOutput out, DataExternalizer externalizer) throws IOException { DataInputOutputUtil.writeINT(out, size()); - for (final ValueIterator valueIterator = getValueIterator(); valueIterator.hasNext();) { + for (final ValueIteratorImpl valueIterator = getValueIterator(); valueIterator.hasNext();) { final Value value = valueIterator.next(); externalizer.save(out, value); Object fileSetObject = valueIterator.getFileSetObject(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueIteratorImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueIteratorImpl.java new file mode 100644 index 000000000000..93e91e53b4ca --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueIteratorImpl.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util.indexing; + +import org.jetbrains.annotations.NotNull; + +/** + * Created by Maxim.Mossienko on 11/22/2016. + */ +interface ValueIteratorImpl extends ValueContainer.ValueIterator { + @NotNull + IntPredicate getValueAssociationPredicate(); + + Object getFileSetObject(); +} diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java index 7e9076282b8e..6464b8a51493 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java @@ -16,6 +16,7 @@ package com.intellij.util.indexing.containers; import com.intellij.util.indexing.DebugAssertions; +import com.intellij.util.indexing.IntPredicate; import com.intellij.util.indexing.ValueContainer; import gnu.trove.TIntProcedure; @@ -266,10 +267,10 @@ public class ChangeBufferingList implements Cloneable { return intContainer.size() == 0; } - public ValueContainer.IntPredicate intPredicate() { - final ValueContainer.IntPredicate predicate = getRandomAccessContainer().intPredicate(); + public IntPredicate intPredicate() { + final IntPredicate predicate = getRandomAccessContainer().intPredicate(); if (checkSet != null) { - return new ValueContainer.IntPredicate() { + return new IntPredicate() { @Override public boolean contains(int id) { boolean answer = predicate.contains(id); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/IdBitSet.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/IdBitSet.java index 357c919f7162..266341b3cb9f 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/IdBitSet.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/IdBitSet.java @@ -16,6 +16,7 @@ package com.intellij.util.indexing.containers; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.indexing.IntPredicate; import com.intellij.util.indexing.ValueContainer; /** @@ -126,8 +127,8 @@ class IdBitSet implements Cloneable, RandomAccessIntContainer { } @Override - public ValueContainer.IntPredicate intPredicate() { - return new ValueContainer.IntPredicate() { + public IntPredicate intPredicate() { + return new IntPredicate() { @Override public boolean contains(int id) { return IdBitSet.this.contains(id); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/IdSet.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/IdSet.java index bbe7ff7891e7..23ad57050113 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/IdSet.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/IdSet.java @@ -15,6 +15,7 @@ */ package com.intellij.util.indexing.containers; +import com.intellij.util.indexing.IntPredicate; import com.intellij.util.indexing.ValueContainer; import gnu.trove.TIntHashSet; @@ -36,8 +37,8 @@ public class IdSet extends TIntHashSet implements RandomAccessIntContainer { } @Override - public ValueContainer.IntPredicate intPredicate() { - return new ValueContainer.IntPredicate() { + public IntPredicate intPredicate() { + return new IntPredicate() { @Override public boolean contains(int id) { return IdSet.this.contains(id); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/RandomAccessIntContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/RandomAccessIntContainer.java index 3618cb97e32e..1bdb1e42ce14 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/RandomAccessIntContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/RandomAccessIntContainer.java @@ -15,6 +15,7 @@ */ package com.intellij.util.indexing.containers; +import com.intellij.util.indexing.IntPredicate; import com.intellij.util.indexing.ValueContainer; /** @@ -25,7 +26,7 @@ interface RandomAccessIntContainer { boolean add(int value); boolean remove(int value); ValueContainer.IntIterator intIterator(); - ValueContainer.IntPredicate intPredicate(); + IntPredicate intPredicate(); void compact(); int size(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/SortedIdSet.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/SortedIdSet.java index fdb459784761..2bd87c729310 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/SortedIdSet.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/SortedIdSet.java @@ -15,6 +15,7 @@ */ package com.intellij.util.indexing.containers; +import com.intellij.util.indexing.IntPredicate; import com.intellij.util.indexing.ValueContainer; import gnu.trove.TIntProcedure; @@ -94,8 +95,8 @@ public class SortedIdSet implements Cloneable, RandomAccessIntContainer { } @Override - public ValueContainer.IntPredicate intPredicate() { - return new ValueContainer.IntPredicate() { + public IntPredicate intPredicate() { + return new IntPredicate() { @Override public boolean contains(int id) { diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java index 230e9cbb62ec..a936a9e3e98d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java @@ -36,7 +36,6 @@ import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectEx; -import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.EmptyRunnable; @@ -66,7 +65,6 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap @Nullable private final ProjectEx myProject; private final CommandProcessor myCommandProcessor; - private final StartupManager myStartupManager; private UndoProvider[] myUndoProviders; private CurrentEditorProvider myEditorProvider; @@ -101,29 +99,21 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap return Registry.intValue("undo.documentUndoLimit"); } - public UndoManagerImpl(Application application, CommandProcessor commandProcessor) { - this(application, null, commandProcessor, null); + public UndoManagerImpl(CommandProcessor commandProcessor) { + this(null, commandProcessor); } - public UndoManagerImpl(Application application, - @Nullable ProjectEx project, - CommandProcessor commandProcessor, - StartupManager startupManager) { + public UndoManagerImpl(@Nullable ProjectEx project, CommandProcessor commandProcessor) { myProject = project; myCommandProcessor = commandProcessor; - myStartupManager = startupManager; - init(application); + if (myProject == null || !myProject.isDefault()) { + runStartupActivity(); + } myMerger = new CommandMerger(this); } - private void init(@NotNull Application application) { - if (myProject == null || application.isUnitTestMode() && !myProject.isDefault()) { - initialize(); - } - } - @Override @NotNull public String getComponentName() { @@ -141,9 +131,6 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap @Override public void projectOpened() { - if (!ApplicationManager.getApplication().isUnitTestMode()) { - initialize(); - } } @Override @@ -158,15 +145,6 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap public void dispose() { } - private void initialize() { - if (myProject == null) { - runStartupActivity(); - } - else { - myStartupManager.registerStartupActivity(this::runStartupActivity); - } - } - private void runStartupActivity() { myEditorProvider = new FocusBasedCurrentEditorProvider(); CommandListener commandListener = new CommandAdapter() { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/PerProjectLaterInvokatorTest.kt b/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/PerProjectLaterInvokatorTest.kt index da9f16ff9731..ce02d4f6cad9 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/PerProjectLaterInvokatorTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/PerProjectLaterInvokatorTest.kt @@ -53,7 +53,7 @@ class RunnableActionsTest : PlatformTestCase() { private val myPerProjectModalDialog = Dialog(null, "Per-project modal dialog", Dialog.ModalityType.DOCUMENT_MODAL) private val myApplicationModalDialog = Dialog(null, "Owned dialog", Dialog.ModalityType.DOCUMENT_MODAL) - fun testModalityStateChangedListener () { + fun _testModalityStateChangedListener () { val enteringOrder = booleanArrayOf(true, true, false, false) val enteringIndex = AtomicInteger(-1) diff --git a/platform/indexing-api/src/com/intellij/util/indexing/DataIndexer.java b/platform/util/src/com/intellij/util/indexing/DataIndexer.java similarity index 100% rename from platform/indexing-api/src/com/intellij/util/indexing/DataIndexer.java rename to platform/util/src/com/intellij/util/indexing/DataIndexer.java diff --git a/platform/core-api/src/com/intellij/util/indexing/ID.java b/platform/util/src/com/intellij/util/indexing/ID.java similarity index 100% rename from platform/core-api/src/com/intellij/util/indexing/ID.java rename to platform/util/src/com/intellij/util/indexing/ID.java diff --git a/platform/indexing-api/src/com/intellij/util/indexing/IndexExtension.java b/platform/util/src/com/intellij/util/indexing/IndexExtension.java similarity index 100% rename from platform/indexing-api/src/com/intellij/util/indexing/IndexExtension.java rename to platform/util/src/com/intellij/util/indexing/IndexExtension.java diff --git a/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java b/platform/util/src/com/intellij/util/indexing/InvertedIndex.java similarity index 69% rename from platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java rename to platform/util/src/com/intellij/util/indexing/InvertedIndex.java index 34b7937cb7a1..6cac01b5311a 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java +++ b/platform/util/src/com/intellij/util/indexing/InvertedIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -16,8 +16,7 @@ package com.intellij.util.indexing; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.util.Processor; +import com.intellij.openapi.util.Computable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,9 +24,19 @@ import org.jetbrains.annotations.Nullable; * @author Eugene Zhuravlev * Date: Dec 24, 2007 */ -public interface AbstractIndex { +public interface InvertedIndex { @NotNull ValueContainer getData(@NotNull Key key) throws StorageException; - boolean processAllKeys(@NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; + /** + * @param inputId *positive* id of content. + */ + @NotNull + Computable update(int inputId, @Nullable Input content); + + void flush() throws StorageException; + + void clear() throws StorageException; + + void dispose(); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/StorageException.java b/platform/util/src/com/intellij/util/indexing/StorageException.java similarity index 100% rename from platform/lang-impl/src/com/intellij/util/indexing/StorageException.java rename to platform/util/src/com/intellij/util/indexing/StorageException.java diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java b/platform/util/src/com/intellij/util/indexing/ValueContainer.java similarity index 74% rename from platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java rename to platform/util/src/com/intellij/util/indexing/ValueContainer.java index 983a4d257c63..2a4076885c1c 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java +++ b/platform/util/src/com/intellij/util/indexing/ValueContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -22,7 +22,6 @@ import org.jetbrains.annotations.NotNull; import java.io.DataOutput; import java.io.IOException; import java.util.Iterator; -import java.util.List; /** * @author Eugene Zhuravlev @@ -41,35 +40,16 @@ public abstract class ValueContainer { IntIterator createCopyInInitialState(); } - public interface IntPredicate { - boolean contains(int id); - } - - @NotNull - public abstract IntIterator getInputIdsIterator(Value value); - - @NotNull - public abstract IntPredicate getValueAssociationPredicate(Value value); - @NotNull public abstract ValueIterator getValueIterator(); public interface ValueIterator extends Iterator { @NotNull IntIterator getInputIdsIterator(); - - @NotNull - IntPredicate getValueAssociationPredicate(); - - Object getFileSetObject(); } - @NotNull - public abstract List toValueList(); - public abstract int size(); - public interface ContainerAction { boolean perform(int id, T value); } @@ -84,15 +64,5 @@ public abstract class ValueContainer { return true; } - private volatile boolean myNeedsCompacting; - - boolean needsCompacting() { - return myNeedsCompacting; - } - - void setNeedsCompacting(boolean value) { - myNeedsCompacting = value; - } - public abstract void saveTo(DataOutput out, DataExternalizer externalizer) throws IOException; } diff --git a/platform/util/src/com/intellij/util/io/VoidDataExternalizer.java b/platform/util/src/com/intellij/util/io/VoidDataExternalizer.java new file mode 100644 index 000000000000..e79bf737b5af --- /dev/null +++ b/platform/util/src/com/intellij/util/io/VoidDataExternalizer.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util.io; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class VoidDataExternalizer implements DataExternalizer { + public static final VoidDataExternalizer INSTANCE = new VoidDataExternalizer(); + + @Override + public void save(@NotNull final DataOutput out, final Void value) throws IOException { + } + + @Override + @Nullable + public Void read(@NotNull final DataInput in) throws IOException { + return null; + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogMessagesTrigramIndex.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogMessagesTrigramIndex.java index 699591c1cb1e..f90961cf903b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogMessagesTrigramIndex.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogMessagesTrigramIndex.java @@ -18,9 +18,9 @@ package com.intellij.vcs.log.data.index; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.text.TrigramBuilder; import com.intellij.util.indexing.DataIndexer; -import com.intellij.util.indexing.ScalarIndexExtension; import com.intellij.util.indexing.StorageException; import com.intellij.util.indexing.ValueContainer; +import com.intellij.util.io.VoidDataExternalizer; import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.impl.FatalErrorHandler; import gnu.trove.THashMap; @@ -38,7 +38,7 @@ public class VcsLogMessagesTrigramIndex extends VcsLogFullDetailsIndex { public VcsLogMessagesTrigramIndex(@NotNull String logId, @NotNull FatalErrorHandler fatalErrorHandler, @NotNull Disposable disposableParent) throws IOException { - super(logId, TRIGRAMS, getVersion(), new TrigramMessageIndexer(), ScalarIndexExtension.VOID_DATA_EXTERNALIZER, + super(logId, TRIGRAMS, getVersion(), new TrigramMessageIndexer(), VoidDataExternalizer.INSTANCE, fatalErrorHandler, disposableParent); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogUserIndex.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogUserIndex.java index 04553a29567d..583096cffc5f 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogUserIndex.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogUserIndex.java @@ -20,8 +20,8 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.DataIndexer; -import com.intellij.util.indexing.ScalarIndexExtension; import com.intellij.util.indexing.StorageException; +import com.intellij.util.io.VoidDataExternalizer; import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.VcsUser; import com.intellij.vcs.log.data.VcsUserRegistryImpl; @@ -45,7 +45,7 @@ public class VcsLogUserIndex extends VcsLogFullDetailsIndex { @NotNull VcsUserRegistryImpl userRegistry, @NotNull FatalErrorHandler consumer, @NotNull Disposable disposableParent) throws IOException { - super(logId, USERS, getVersion(), new UserIndexer(userRegistry), ScalarIndexExtension.VOID_DATA_EXTERNALIZER, + super(logId, USERS, getVersion(), new UserIndexer(userRegistry), VoidDataExternalizer.INSTANCE, consumer, disposableParent); myUserRegistry = userRegistry; ((UserIndexer)myIndexer).setFatalErrorConsumer(e -> consumer.consume(this, e)); diff --git a/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java b/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java index 230ffce91873..d9dfa9f89976 100644 --- a/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java +++ b/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java @@ -90,11 +90,17 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp final PsiExpression candidate = canBeMethodReferenceProblem(expression.getParameterList().getParameters(), functionalInterfaceType, null, methodRefCandidate); if (candidate != null) { - ProblemHighlightType errorOrWarning = checkQualifier(methodRefCandidate) ? ProblemHighlightType.GENERIC_ERROR_OR_WARNING - : ProblemHighlightType.INFORMATION; + PsiExpression qualifier = + methodRefCandidate instanceof PsiMethodCallExpression ? ((PsiMethodCallExpression)methodRefCandidate).getMethodExpression().getQualifierExpression() + : methodRefCandidate instanceof PsiNewExpression + ? ((PsiNewExpression)methodRefCandidate).getQualifier() + : null; + boolean safeQualifier = checkQualifier(qualifier); + ProblemHighlightType errorOrWarning = safeQualifier ? ProblemHighlightType.GENERIC_ERROR_OR_WARNING + : ProblemHighlightType.INFORMATION; holder.registerProblem(InspectionProjectProfileManager.isInformationLevel(getShortName(), expression) ? expression : candidate, "Can be replaced with method reference", - errorOrWarning, new ReplaceWithMethodRefFix()); + errorOrWarning, new ReplaceWithMethodRefFix(safeQualifier ? "" : " (may change semantics)")); } } } @@ -308,7 +314,7 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp return tryConvertToMethodReference(lambda, candidate); } - public static boolean checkQualifier(PsiElement qualifier) { + public static boolean checkQualifier(@Nullable PsiElement qualifier) { if (qualifier == null) { return true; } @@ -564,6 +570,19 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp } private static class ReplaceWithMethodRefFix implements LocalQuickFix { + private String mySuffix; + + public ReplaceWithMethodRefFix(String suffix) { + mySuffix = suffix; + } + + @Nls + @NotNull + @Override + public String getName() { + return getFamilyName() + mySuffix; + } + @NotNull @Override public String getFamilyName() { diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java index 7bd009b720ef..6fba69f56e06 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java @@ -110,7 +110,7 @@ public class UnicodeUnescapeIntention extends Intention { /** * see JLS 3.3. Unicode Escapes */ - private static int indexOfUnicodeEscape(@NotNull String text, int offset) { + static int indexOfUnicodeEscape(@NotNull String text, int offset) { final int length = text.length(); for (int i = 0; i < length; i++) { final char c = text.charAt(i); @@ -143,6 +143,8 @@ public class UnicodeUnescapeIntention extends Intention { StringUtil.isHexDigit(text.charAt(nextChar + 3))) { final int escapeEnd = nextChar + 4; if (offset <= escapeEnd) { + final char d = (char)Integer.parseInt(text.substring(nextChar, nextChar + 4), 16); + if (d == '\r') return -1; // carriage return not allowed return i; } } diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/unicode/unescape/NoCarriageReturn.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/unicode/unescape/NoCarriageReturn.java new file mode 100644 index 000000000000..045e900b2bbb --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/unicode/unescape/NoCarriageReturn.java @@ -0,0 +1 @@ +// \u000D \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/unicode/UnicodeUnescapeIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/unicode/UnicodeUnescapeIntentionTest.java index bb68178ed414..06209bbf5ac7 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/unicode/UnicodeUnescapeIntentionTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/unicode/UnicodeUnescapeIntentionTest.java @@ -29,6 +29,7 @@ public class UnicodeUnescapeIntentionTest extends IPPTestCase { public void testSurrogatePairs2() { doTest(); } public void testNoException() { assertIntentionNotAvailable(); } public void testU() { assertIntentionNotAvailable(); } + public void testNoCarriageReturn() { assertIntentionNotAvailable(); } @Override protected String getRelativePath() { diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java index aa08d59c007b..faaa750fea79 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java @@ -26,6 +26,7 @@ import com.intellij.openapi.vcs.VcsNotifier; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; import git4idea.GitUtil; import git4idea.commands.*; import git4idea.config.GitVcsSettings; @@ -38,6 +39,7 @@ import javax.swing.event.HyperlinkEvent; import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; import static git4idea.util.GitUIUtil.code; import static java.util.Arrays.stream; @@ -53,8 +55,6 @@ import static java.util.Arrays.stream; */ class GitCheckoutOperation extends GitBranchOperation { - public static final String ROLLBACK_PROPOSAL_FORMAT = "You may rollback (checkout back to previous branch) not to let branches diverge."; - @NotNull private final String myStartPointReference; private final boolean myDetach; private final boolean myRefShouldBeValid; @@ -192,8 +192,15 @@ class GitCheckoutOperation extends GitBranchOperation { @NotNull @Override protected String getRollbackProposal() { + Collection distinctPrevBranches = getSuccessfulRepositories().stream(). + map(myCurrentHeads::get). + distinct(). + collect(Collectors.toList()); + String previousBranch = distinctPrevBranches.size() == 1 ? ContainerUtil.getFirstItem(distinctPrevBranches) : "previous branch"; + String rollBackProposal = "You may rollback (checkout back to " + previousBranch + ") not to let branches diverge."; return "However checkout has succeeded for the following " + repositories() + ":
" + - successfulRepositoriesJoined() + "
" + ROLLBACK_PROPOSAL_FORMAT; + successfulRepositoriesJoined() + "
" + + rollBackProposal; } @NotNull diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java index cd1d744eb507..a4393c8dec05 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java @@ -17,9 +17,10 @@ package org.jetbrains.plugins.gradle.config; import com.intellij.compiler.options.CompileStepBeforeRun; import com.intellij.compiler.options.CompileStepBeforeRunNoErrorCheck; -import com.intellij.execution.*; +import com.intellij.execution.CantRunException; +import com.intellij.execution.Location; +import com.intellij.execution.RunManagerEx; import com.intellij.execution.configurations.JavaParameters; -import com.intellij.execution.configurations.RunProfile; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.externalSystem.psi.search.ExternalModuleBuildGlobalSearchScope; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; @@ -172,12 +173,10 @@ public class GradleScriptType extends GroovyRunnableScriptType { } @Override - public boolean ensureRunnerConfigured(@Nullable Module module, RunProfile profile, Executor executor, final Project project) throws ExecutionException { - if (project != null && profile instanceof GroovyScriptRunConfiguration) { - GroovyScriptRunConfiguration configuration = (GroovyScriptRunConfiguration)profile; - String parameters = configuration.getProgramParameters(); - if (parameters != null) { - // TODO den implement + public void ensureRunnerConfigured(@NotNull GroovyScriptRunConfiguration configuration) { + String parameters = configuration.getProgramParameters(); + if (parameters != null) { + // TODO den implement // GradleTasksList list = GradleUtil.getToolWindowElement(GradleTasksList.class, project, ExternalSystemDataKeys.RECENT_TASKS_LIST); // if (list != null) { // ExternalSystemTaskDescriptor descriptor = new ExternalSystemTaskDescriptor(parameters, null); @@ -185,7 +184,6 @@ public class GradleScriptType extends GroovyRunnableScriptType { // list.setFirst(descriptor); // GradleLocalSettings.getInstance(project).setRecentTasks(list.getModel().getTasks()); // } - } } final GradleInstallationManager libraryManager = ServiceManager.getService(GradleInstallationManager.class); // TODO den implement @@ -203,7 +201,6 @@ public class GradleScriptType extends GroovyRunnableScriptType { // return false; // } // } - return true; } @Override diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyRunnerPsiUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyRunnerPsiUtil.java index 07b002510a2d..967a3f02c12e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyRunnerPsiUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyRunnerPsiUtil.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.groovy.lang.psi.util; +import com.intellij.openapi.project.DumbService; import com.intellij.psi.*; import com.intellij.psi.util.PsiMethodUtil; import com.intellij.psi.util.PsiTreeUtil; @@ -27,6 +28,7 @@ public class GroovyRunnerPsiUtil { @Nullable public static PsiClass getRunningClass(@Nullable PsiElement element) { if (element == null) return null; + if (DumbService.isDumb(element.getProject())) return null; final PsiFile file = element.getContainingFile(); if (!(file instanceof GroovyFile)) return null; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantRunner.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantRunner.java index d75d2e38eecd..e15cfcf51834 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantRunner.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantRunner.java @@ -16,19 +16,16 @@ package org.jetbrains.plugins.groovy.gant; import com.intellij.execution.CantRunException; -import com.intellij.execution.Executor; import com.intellij.execution.configurations.JavaParameters; -import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.configurations.RuntimeConfigurationException; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.libraries.LibraryUtil; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; -import icons.JetgroovyIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.config.GroovyConfigUtils; @@ -55,20 +52,13 @@ public class GantRunner extends GroovyScriptRunner { } @Override - public boolean ensureRunnerConfigured(@Nullable Module module, RunProfile profile, Executor executor, final Project project) { - if (GantUtils.getSDKInstallPath(module, project).isEmpty()) { - int result = Messages - .showOkCancelDialog("Gant is not configured. Do you want to configure it?", "Configure Gant SDK", - JetgroovyIcons.Groovy.Gant_16x16); - if (result == Messages.OK) { - ShowSettingsUtil.getInstance().editConfigurable(project, new GantConfigurable(project)); - } - if (GantUtils.getSDKInstallPath(module, project).isEmpty()) { - return false; - } + public void ensureRunnerConfigured(@NotNull GroovyScriptRunConfiguration configuration) throws RuntimeConfigurationException { + Project project = configuration.getProject(); + if (GantUtils.getSDKInstallPath(configuration.getModule(), project).isEmpty()) { + RuntimeConfigurationException e = new RuntimeConfigurationException("Gant is not configured"); + e.setQuickFix(() -> ShowSettingsUtil.getInstance().editConfigurable(project, new GantConfigurable(project))); + throw e; } - - return true; } private static String getGantConfPath(final String gantHome) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/DefaultGroovyScriptRunner.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/DefaultGroovyScriptRunner.java index 5c8421fec2f1..8c573979dd7c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/DefaultGroovyScriptRunner.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/DefaultGroovyScriptRunner.java @@ -17,14 +17,10 @@ package org.jetbrains.plugins.groovy.runner; import com.intellij.execution.CantRunException; -import com.intellij.execution.ExecutionException; -import com.intellij.execution.Executor; import com.intellij.execution.configurations.JavaParameters; -import com.intellij.execution.configurations.RunProfile; -import com.intellij.execution.runners.ExecutionUtil; +import com.intellij.execution.configurations.RuntimeConfigurationException; import com.intellij.execution.util.ScriptFileUtil; import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ui.configuration.ClasspathEditor; import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; import com.intellij.openapi.util.Comparing; @@ -52,17 +48,17 @@ public class DefaultGroovyScriptRunner extends GroovyScriptRunner { } @Override - public boolean ensureRunnerConfigured(@Nullable Module module, RunProfile profile, Executor executor, final Project project) throws ExecutionException { + public void ensureRunnerConfigured(@NotNull GroovyScriptRunConfiguration configuration) throws RuntimeConfigurationException { + Module module = configuration.getModule(); if (module == null) { - throw new ExecutionException("Module is not specified"); + throw new RuntimeConfigurationException("Module is not specified"); } if (LibrariesUtil.getGroovyHomePath(module) == null) { - ExecutionUtil.handleExecutionError(project, executor.getToolWindowId(), profile, new ExecutionException("Groovy is not configured")); - ModulesConfigurator.showDialog(module.getProject(), module.getName(), ClasspathEditor.NAME); - return false; + RuntimeConfigurationException e = new RuntimeConfigurationException("Groovy is not configured for module '" + module.getName() + "'"); + e.setQuickFix(() -> ModulesConfigurator.showDialog(module.getProject(), module.getName(), ClasspathEditor.NAME)); + throw e; } - return true; } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.form b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.form index c88ca66580fe..c082d99f08b8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.form +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.form @@ -1,104 +1,63 @@
- + - + - + - + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + - - - - - - - - - - - - + - + @@ -107,12 +66,17 @@ - + + + + + + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.java index 7ad7bc896c0c..423a55b1ead0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyRunConfigurationEditor.java @@ -17,116 +17,123 @@ package org.jetbrains.plugins.groovy.runner; import com.intellij.application.options.ModulesComboBox; -import com.intellij.execution.configuration.EnvironmentVariablesComponent; -import com.intellij.ide.util.BrowseFilesListener; -import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.execution.ui.CommonJavaParametersPanel; +import com.intellij.execution.ui.DefaultJreSelector.SdkFromModuleDependencies; +import com.intellij.execution.ui.JrePathEditor; +import com.intellij.execution.util.ScriptFileUtil; +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.ui.LabeledComponent; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.FieldPanel; +import com.intellij.ui.DocumentAdapter; import com.intellij.ui.PanelWithAnchor; -import com.intellij.ui.RawCommandLineEditor; -import com.intellij.ui.components.JBLabel; +import com.intellij.util.ui.UIUtil; +import kotlin.jvm.functions.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyFileType; import javax.swing.*; -import java.awt.*; +import javax.swing.event.DocumentEvent; public class GroovyRunConfigurationEditor extends SettingsEditor implements PanelWithAnchor { - private ModulesComboBox myModulesBox; + private JPanel myMainPanel; - private RawCommandLineEditor myVMParameters; - private RawCommandLineEditor myParameters; - private JPanel scriptPathPanel; - private JPanel workDirPanel; + + private LabeledComponent myScriptPathComponent; + private CommonJavaParametersPanel myCommonJavaParametersPanel; + + private LabeledComponent myModulesComboBoxComponent; + private JrePathEditor myJrePathEditor; + private JCheckBox myDebugCB; - private EnvironmentVariablesComponent myEnvVariables; - private JBLabel myScriptParametersLabel; private JCheckBox myAddClasspathCB; - private final JTextField scriptPathField; - private final JTextField workDirField; - private JComponent anchor; - public GroovyRunConfigurationEditor() { + private JComponent myAnchor; - scriptPathField = new JTextField(); - final BrowseFilesListener scriptBrowseListener = new BrowseFilesListener(scriptPathField, - "Script Path", - "Specify path to script", - new FileChooserDescriptor(true, false, false, false, false, false) { - @Override - public boolean isFileSelectable(VirtualFile file) { - return file.getFileType() == GroovyFileType.GROOVY_FILE_TYPE; + public GroovyRunConfigurationEditor(@NotNull Project project) { + final TextFieldWithBrowseButton scriptPath = myScriptPathComponent.getComponent(); + scriptPath.addBrowseFolderListener( + "Script Path", "Specify path to script", project, + FileChooserDescriptorFactory.createSingleFileDescriptor(GroovyFileType.GROOVY_FILE_TYPE) + ); + + final ModulesComboBox modulesComboBox = myModulesComboBoxComponent.getComponent(); + modulesComboBox.addActionListener(e -> myCommonJavaParametersPanel.setModuleContext(modulesComboBox.getSelectedModule())); + ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); + Function0 productionOnly = () -> { + VirtualFile script = ScriptFileUtil.findScriptFileByPath(scriptPath.getText()); + return script != null && !fileIndex.isInTestSourceContent(script); + }; + myJrePathEditor.setDefaultJreSelector(new SdkFromModuleDependencies(modulesComboBox, productionOnly) { + @Override + public void addChangeListener(@NotNull Runnable listener) { + super.addChangeListener(listener); + scriptPath.getChildComponent().getDocument().addDocumentListener( + new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + listener.run(); + } } - }); - final FieldPanel scriptFieldPanel = new FieldPanel(scriptPathField, null, null, scriptBrowseListener, null); - scriptPathPanel.setLayout(new BorderLayout()); - scriptPathPanel.add(scriptFieldPanel, BorderLayout.CENTER); - - workDirField = new JTextField(); - final BrowseFilesListener workDirBrowseFilesListener = new BrowseFilesListener(workDirField, - "Working directory", - "Specify working directory", - BrowseFilesListener.SINGLE_DIRECTORY_DESCRIPTOR); - final FieldPanel workDirFieldPanel = new FieldPanel(workDirField, null, null, workDirBrowseFilesListener, null); - workDirPanel.setLayout(new BorderLayout()); - workDirPanel.add(workDirFieldPanel, BorderLayout.CENTER); - - setAnchor(myEnvVariables.getLabel()); + ); + } + }); + myAnchor = UIUtil.mergeComponentsWithAnchor( + myScriptPathComponent, + myCommonJavaParametersPanel, + myModulesComboBoxComponent, + myJrePathEditor + ); } @Override public void resetEditorFrom(@NotNull GroovyScriptRunConfiguration configuration) { - myVMParameters.setDialogCaption("VM Options"); - myVMParameters.setText(configuration.getVMParameters()); + myScriptPathComponent.getComponent().setText(configuration.getScriptPath()); + myCommonJavaParametersPanel.reset(configuration); - myParameters.setDialogCaption("Script Parameters"); - myParameters.setText(configuration.getProgramParameters()); + myModulesComboBoxComponent.getComponent().setModules(configuration.getValidModules()); + myModulesComboBoxComponent.getComponent().setSelectedModule(configuration.getConfigurationModule().getModule()); + myJrePathEditor.setPathOrName(configuration.getAlternativeJrePath(), configuration.isAlternativeJrePathEnabled()); - scriptPathField.setText(configuration.getScriptPath()); - workDirField.setText(configuration.getWorkDir()); - - myDebugCB.setEnabled(true); myDebugCB.setSelected(configuration.isDebugEnabled()); - myAddClasspathCB.setSelected(configuration.isAddClasspathToTheRunner()); - - myModulesBox.setModules(configuration.getValidModules()); - myModulesBox.setSelectedModule(configuration.getModule()); - - myEnvVariables.setEnvs(configuration.getEnvs()); } @Override public void applyEditorTo(@NotNull GroovyScriptRunConfiguration configuration) throws ConfigurationException { - configuration.setModule(myModulesBox.getSelectedModule()); - configuration.setVMParameters(myVMParameters.getText()); + configuration.setScriptPath(myScriptPathComponent.getComponent().getText().trim()); + myCommonJavaParametersPanel.applyTo(configuration); + + configuration.setModule(myModulesComboBoxComponent.getComponent().getSelectedModule()); + configuration.setAlternativeJrePathEnabled(myJrePathEditor.isAlternativeJreSelected()); + configuration.setAlternativeJrePath(myJrePathEditor.getJrePathOrName()); + configuration.setDebugEnabled(myDebugCB.isSelected()); configuration.setAddClasspathToTheRunner(myAddClasspathCB.isSelected()); - configuration.setProgramParameters(myParameters.getText()); - configuration.setScriptPath(scriptPathField.getText().trim()); - configuration.setWorkDir(workDirField.getText().trim()); - configuration.setEnvs(myEnvVariables.getEnvs()); } @Override @NotNull public JComponent createEditor() { - myDebugCB.setEnabled(true); - myDebugCB.setSelected(false); return myMainPanel; } @Override public JComponent getAnchor() { - return anchor; + return myAnchor; } @Override public void setAnchor(JComponent anchor) { - this.anchor = anchor; - myScriptParametersLabel.setAnchor(anchor); - myEnvVariables.setAnchor(anchor); + myAnchor = anchor; + myScriptPathComponent.setAnchor(anchor); + myCommonJavaParametersPanel.setAnchor(anchor); + myModulesComboBoxComponent.setAnchor(anchor); + myJrePathEditor.setAnchor(anchor); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfiguration.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfiguration.java index 57db308d862a..ef5c33636332 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfiguration.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfiguration.java @@ -15,16 +15,19 @@ */ package org.jetbrains.plugins.groovy.runner; -import com.intellij.execution.*; +import com.intellij.execution.CommonJavaRunConfigurationParameters; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.Executor; +import com.intellij.execution.ExternalizablePath; import com.intellij.execution.configurations.*; import com.intellij.execution.process.OSProcessHandler; import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.util.JavaParametersUtil; import com.intellij.execution.util.ProgramParametersUtil; import com.intellij.execution.util.ScriptFileUtil; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.options.SettingsEditor; @@ -36,6 +39,7 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.JDOMExternalizer; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; @@ -71,7 +75,6 @@ import java.util.Map; public class GroovyScriptRunConfiguration extends ModuleBasedConfiguration implements CommonJavaRunConfigurationParameters, RefactoringListenerProvider { - private static final Logger LOG = Logger.getInstance(GroovyScriptRunConfiguration.class); private String vmParams; private String workDir; private boolean isDebugEnabled; @@ -81,28 +84,23 @@ public class GroovyScriptRunConfiguration extends ModuleBasedConfiguration envs = new LinkedHashMap<>(); public boolean passParentEnv = true; + private boolean myAlternativeJrePathEnabled; + private @Nullable String myAlternativeJrePath; + public GroovyScriptRunConfiguration(final String name, final Project project, final ConfigurationFactory factory) { super(name, new RunConfigurationModule(project), factory); workDir = PathUtil.getLocalPath(project.getBaseDir()); } - public void setWorkDir(String dir) { - workDir = dir; - } - - public String getWorkDir() { - return workDir; - } - @Nullable public Module getModule() { - return getConfigurationModule().getModule(); + return ObjectUtils.chooseNotNull(getConfigurationModule().getModule(), ContainerUtil.getFirstItem(getValidModules())); } @Override public Collection getValidModules() { Module[] modules = ModuleManager.getInstance(getProject()).getModules(); - final GroovyScriptRunner scriptRunner = findConfiguration(); + final GroovyScriptRunner scriptRunner = getScriptRunner(); if (scriptRunner == null) { return Arrays.asList(modules); } @@ -118,21 +116,20 @@ public class GroovyScriptRunConfiguration extends ModuleBasedConfiguration getConfigurationEditor() { - return new GroovyRunConfigurationEditor(); + return new GroovyRunConfigurationEditor(getProject()); } @Override public void checkConfiguration() throws RuntimeConfigurationException { super.checkConfiguration(); - final PsiClass toRun = getScriptClass(); + + final String scriptPath = getScriptPath(); + + final VirtualFile script = ScriptFileUtil.findScriptFileByPath(scriptPath); + if (script == null) throw new RuntimeConfigurationException("Cannot find script " + scriptPath); + + final GroovyScriptRunner scriptRunner = getScriptRunner(); + if (scriptRunner == null) throw new RuntimeConfigurationException("Unknown script type " + scriptPath); + + scriptRunner.ensureRunnerConfigured(this); + + final PsiFile file = PsiManager.getInstance(getProject()).findFile(script); + final PsiClass toRun = GroovyRunnerPsiUtil.getRunningClass(file); if (toRun == null) { throw new RuntimeConfigurationWarning(GroovyBundle.message("class.does.not.exist")); } @@ -315,6 +317,7 @@ public class GroovyScriptRunConfiguration extends ModuleBasedConfiguration entry : task.getTaskFiles().entrySet()) { String name = entry.getKey(); - VirtualFile answerFile = taskDir.findChild(name); + VirtualFile answerFile = taskDir.findFileByRelativePath(name); if (answerFile == null) { continue; } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java index c34c6260669f..e1dc9fc980fd 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java @@ -44,7 +44,7 @@ public class CCVirtualFileListener extends VirtualFileAdapter { return; } - String name = createdFile.getName(); + String taskRelativePath = StudyUtils.pathRelativeToTask(createdFile); CCLanguageManager manager = CCUtils.getStudyLanguageManager(course); if (manager != null && manager.doNotPackFile(new File(createdFile.getPath()))) { @@ -52,10 +52,10 @@ public class CCVirtualFileListener extends VirtualFileAdapter { } if (CCUtils.isTestsFile(project, createdFile) - || StudyUtils.isTaskDescriptionFile(name) - || name.contains(EduNames.WINDOW_POSTFIX) - || name.contains(EduNames.WINDOWS_POSTFIX) - || name.contains(EduNames.ANSWERS_POSTFIX)) { + || StudyUtils.isTaskDescriptionFile(taskRelativePath) + || taskRelativePath.contains(EduNames.WINDOW_POSTFIX) + || taskRelativePath.contains(EduNames.WINDOWS_POSTFIX) + || taskRelativePath.contains(EduNames.ANSWERS_POSTFIX)) { return; } VirtualFile taskVF = StudyUtils.getTaskDir(createdFile); @@ -69,7 +69,7 @@ public class CCVirtualFileListener extends VirtualFileAdapter { CCUtils.createResourceFile(createdFile, course, taskVF); - task.addTaskFile(name, 1); + task.addTaskFile(taskRelativePath, 1); } @Override @@ -136,6 +136,6 @@ public class CCVirtualFileListener extends VirtualFileAdapter { if (task == null) { return; } - task.getTaskFiles().remove(removedTaskFile.getName()); + task.getTaskFiles().remove(StudyUtils.pathRelativeToTask(removedTaskFile)); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java index 925bc592fea3..457970c95746 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java @@ -55,8 +55,9 @@ public class CCAddAsTaskFile extends CCTaskFileActionBase { if (myTaskFile != null) { myTask.addTaskFile(myTaskFile); } else { - myTask.addTaskFile(myFile.getName(), myTask.getTaskFiles().size()); - myTaskFile = myTask.getTaskFile(myFile.getName()); + final String taskRelativePath = StudyUtils.pathRelativeToTask(myFile); + myTask.addTaskFile(taskRelativePath, myTask.getTaskFiles().size()); + myTaskFile = myTask.getTaskFile(taskRelativePath); } CCUtils.createResourceFile(myFile, myCourse, StudyUtils.getTaskDir(myFile)); ProjectView.getInstance(myProject).refresh(); diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java index 244a0b984384..425ba8a1ea99 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java @@ -137,7 +137,7 @@ public class CCCreateCourseArchive extends DumbAwareAction { transformSubtaskTestsToTextFiles(studentFileDir); } for (String taskFile : task.getTaskFiles().keySet()) { - VirtualFile answerFile = taskDir.findChild(taskFile); + VirtualFile answerFile = taskDir.findFileByRelativePath(taskFile); if (answerFile == null) { continue; } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java index 91e13d9314d0..1f5a02a45d7d 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java @@ -130,7 +130,7 @@ public class CCFromCourseArchive extends DumbAwareAction { @NotNull final Map.Entry taskFileEntry) { final String name = taskFileEntry.getKey(); final TaskFile taskFile = taskFileEntry.getValue(); - VirtualFile file = userFileDir.findChild(name); + VirtualFile file = userFileDir.findFileByRelativePath(name); assert file != null; final Document originDocument = FileDocumentManager.getInstance().getDocument(file); if (originDocument == null) { diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java index b183eeda7b38..45496606bfe8 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java @@ -58,7 +58,7 @@ public class CCHideFromStudent extends CCTaskFileActionBase { @Override public void undo() throws UnexpectedUndoException { - myTask.getTaskFiles().put(myFile.getName(), myTaskFile); + myTask.getTaskFiles().put(StudyUtils.pathRelativeToTask(myFile), myTaskFile); CCUtils.createResourceFile(myFile, myCourse, StudyUtils.getTaskDir(myFile)); if (!myTaskFile.getAnswerPlaceholders().isEmpty() && FileEditorManager.getInstance(myProject).isFileOpen(myFile)) { for (FileEditor fileEditor : FileEditorManager.getInstance(myProject).getEditors(myFile)) { @@ -92,8 +92,8 @@ public class CCHideFromStudent extends CCTaskFileActionBase { } } } - String name = file.getName(); - VirtualFile patternFile = StudyUtils.getPatternFile(taskFile, name); + String taskRelativePath = StudyUtils.pathRelativeToTask(file); + VirtualFile patternFile = StudyUtils.getPatternFile(taskFile, taskRelativePath); ApplicationManager.getApplication().runWriteAction(() -> { if (patternFile != null) { try { @@ -104,7 +104,7 @@ public class CCHideFromStudent extends CCTaskFileActionBase { } } }); - taskFiles.remove(name); + taskFiles.remove(taskRelativePath); } @Override diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCChangePlaceholderVisibility.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCChangePlaceholderVisibility.java index eb0c7dfde710..2366f569acbc 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCChangePlaceholderVisibility.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCChangePlaceholderVisibility.java @@ -2,6 +2,7 @@ package com.jetbrains.edu.coursecreator.actions.placeholder; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.command.undo.BasicUndoableAction; import com.intellij.openapi.command.undo.UnexpectedUndoException; import com.intellij.openapi.editor.Document; @@ -39,7 +40,7 @@ public abstract class CCChangePlaceholderVisibility extends CCAnswerPlaceholderA public void redo() throws UnexpectedUndoException { setVisible(placeholder, !isVisible(), state); } - }); + }, UndoConfirmationPolicy.REQUEST_CONFIRMATION); } private void setVisible(AnswerPlaceholder placeholder, boolean visible, CCState state) { @@ -97,10 +98,14 @@ public abstract class CCChangePlaceholderVisibility extends CCAnswerPlaceholderA return; } Integer minSubtaskIndex = Collections.min(placeholder.getSubtaskInfos().keySet()); - if (placeholder.isActive() && minSubtaskIndex != 0 && minSubtaskIndex == task.getActiveSubtaskIndex() && isAvailable(placeholder)) { + if (canChangeState(placeholder, task, minSubtaskIndex)) { presentation.setEnabledAndVisible(true); } } + private boolean canChangeState(@NotNull AnswerPlaceholder placeholder, @NotNull Task task, int minSubtaskIndex) { + return placeholder.isActive() && minSubtaskIndex != 0 && minSubtaskIndex == task.getActiveSubtaskIndex() && isAvailable(placeholder); + } + protected abstract boolean isAvailable(AnswerPlaceholder placeholder); } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCEditAnswerPlaceholder.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCEditAnswerPlaceholder.java index 11fac1e9b018..ef5834075af1 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCEditAnswerPlaceholder.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCEditAnswerPlaceholder.java @@ -3,6 +3,7 @@ package com.jetbrains.edu.coursecreator.actions.placeholder; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; @@ -29,7 +30,9 @@ public class CCEditAnswerPlaceholder extends CCAnswerPlaceholderAction { CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder.getTaskText(), answerPlaceholder.getHints()); dlg.setTitle("Edit Answer Placeholder"); if (dlg.showAndGet()) { - answerPlaceholder.setTaskText(dlg.getTaskText()); + final String answerPlaceholderText = dlg.getTaskText(); + answerPlaceholder.setTaskText(answerPlaceholderText); + answerPlaceholder.setLength(answerPlaceholder.getActiveSubtaskInfo().isNeedInsertText() ? 0 : StringUtil.notNullize(answerPlaceholderText).length()); answerPlaceholder.setHints(dlg.getHints()); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCCourseDirectoryNode.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCCourseDirectoryNode.java index 04cd3f4b051c..bb06f8e8741b 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCCourseDirectoryNode.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCCourseDirectoryNode.java @@ -1,6 +1,7 @@ package com.jetbrains.edu.coursecreator.projectView; import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.ide.projectView.impl.nodes.PsiFileNode; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.project.Project; @@ -11,7 +12,6 @@ import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.StudyItem; import com.jetbrains.edu.learning.projectView.CourseDirectoryNode; -import com.jetbrains.edu.learning.projectView.StudyDirectoryNode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -45,7 +45,7 @@ public class CCCourseDirectoryNode extends CourseDirectoryNode { } @Override - public StudyDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory directory) { + public PsiDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory directory) { return new CCLessonDirectoryNode(myProject, directory, myViewSettings, ((Lesson)item)); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java new file mode 100644 index 000000000000..28334c43f9a8 --- /dev/null +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java @@ -0,0 +1,62 @@ +package com.jetbrains.edu.coursecreator.projectView; + +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.learning.StudyLanguageManager; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseFormat.StudyItem; +import com.jetbrains.edu.learning.projectView.DirectoryNode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class CCDirectoryNode extends DirectoryNode { + public CCDirectoryNode(@NotNull Project project, + PsiDirectory value, + ViewSettings viewSettings) { + super(project, value, viewSettings); + } + + @Override + public boolean canNavigate() { + return true; + } + + @Nullable + @Override + public AbstractTreeNode modifyChildNode(AbstractTreeNode childNode) { + final AbstractTreeNode node = super.modifyChildNode(childNode); + if (node != null) return node; + Object value = childNode.getValue(); + if (value instanceof PsiElement) { + PsiFile psiFile = ((PsiElement) value).getContainingFile(); + VirtualFile virtualFile = psiFile.getVirtualFile(); + + Course course = StudyTaskManager.getInstance(myProject).getCourse(); + if (course == null) { + return null; + } + StudyLanguageManager manager = StudyUtils.getLanguageManager(course); + if (manager == null) { + return new CCStudentInvisibleFileNode(myProject, psiFile, myViewSettings); + } + if (!CCUtils.isTestsFile(myProject, virtualFile)) { + return new CCStudentInvisibleFileNode(myProject, psiFile, myViewSettings); + } + } + return null; + } + + @Override + public PsiDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory value) { + return new CCDirectoryNode(myProject, value, myViewSettings); + } +} diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCLessonDirectoryNode.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCLessonDirectoryNode.java index 1be30f7613cb..07fef6bd43d2 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCLessonDirectoryNode.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCLessonDirectoryNode.java @@ -1,13 +1,13 @@ package com.jetbrains.edu.coursecreator.projectView; import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.StudyItem; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.projectView.LessonDirectoryNode; -import com.jetbrains.edu.learning.projectView.StudyDirectoryNode; import org.jetbrains.annotations.NotNull; public class CCLessonDirectoryNode extends LessonDirectoryNode { @@ -19,7 +19,7 @@ public class CCLessonDirectoryNode extends LessonDirectoryNode { } @Override - public StudyDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory directory) { + public PsiDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory directory) { return new CCTaskDirectoryNode(myProject, directory, myViewSettings, ((Task)item)); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTaskDirectoryNode.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTaskDirectoryNode.java index 69a7b664b840..93d9ca6bec11 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTaskDirectoryNode.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTaskDirectoryNode.java @@ -1,6 +1,7 @@ package com.jetbrains.edu.coursecreator.projectView; import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; @@ -14,6 +15,7 @@ import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseFormat.StudyItem; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.projectView.TaskDirectoryNode; import org.jetbrains.annotations.NotNull; @@ -95,4 +97,9 @@ public class CCTaskDirectoryNode extends TaskDirectoryNode { int stepIndex = Integer.valueOf(nameWithoutExtension.substring(EduNames.SUBTASK_MARKER.length() + stepMarkerStart)); return stepIndex == myTask.getActiveSubtaskIndex(); } + + @Override + public PsiDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory value) { + return new CCDirectoryNode(myProject, value, myViewSettings); + } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java index 328d2e462294..2764d192f3a9 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java @@ -51,7 +51,7 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur @Override public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) { Task task = getTask(file); - setTaskText(task, file.getParent()); + setTaskText(task, StudyUtils.getTaskDir(file)); } @Override @@ -69,7 +69,7 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur VirtualFile file = event.getNewFile(); if (file != null) { Task task = getTask(file); - setTaskText(task, file.getParent()); + setTaskText(task, StudyUtils.getTaskDir(file)); } toolWindow.setBottomComponent(null); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java index 18c21ff1e270..8b81440ed71d 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java @@ -224,7 +224,7 @@ public class StudyProjectComponent implements ProjectComponent { private static void copyFile(@NotNull final File from, @NotNull final File to) { if (from.exists()) { try { - FileUtil.copy(from, to); + FileUtil.copyFileOrDir(from, to); } catch (IOException e) { LOG.warn("Failed to copy " + from.getName()); @@ -326,7 +326,7 @@ public class StudyProjectComponent implements ProjectComponent { public void fileCreated(@NotNull VirtualFileEvent event) { if (myProject.isDisposed()) return; final VirtualFile createdFile = event.getFile(); - final VirtualFile taskDir = createdFile.getParent(); + final VirtualFile taskDir = StudyUtils.getTaskDir(createdFile); final Course course = StudyTaskManager.getInstance(myProject).getCourse(); if (course == null || !EduNames.STUDY.equals(course.getCourseMode())) { return; @@ -345,7 +345,7 @@ public class StudyProjectComponent implements ProjectComponent { final TaskFile taskFile = new TaskFile(); taskFile.initTaskFile(task, false); taskFile.setUserCreated(true); - final String name = createdFile.getName(); + final String name = FileUtil.getRelativePath(taskDir.getPath(), createdFile.getPath(), File.separatorChar); taskFile.name = name; //TODO: put to other steps as well task.getTaskFiles().put(name, taskFile); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyState.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyState.java index f4cb42a1340c..26706b25339c 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyState.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyState.java @@ -21,7 +21,7 @@ public class StudyState { myEditor = studyEditor != null ? studyEditor.getEditor() : null; myTaskFile = studyEditor != null ? studyEditor.getTaskFile() : null; myVirtualFile = myEditor != null ? FileDocumentManager.getInstance().getFile(myEditor.getDocument()) : null; - myTaskDir = myVirtualFile != null ? myVirtualFile.getParent() : null; + myTaskDir = myVirtualFile != null ? StudyUtils.getTaskDir(myVirtualFile) : null; myTask = myTaskFile != null ? myTaskFile.getTask() : null; } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java index f595eaaa7183..e3eb2d4892eb 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java @@ -2,6 +2,8 @@ package com.jetbrains.edu.learning; import com.intellij.ide.projectView.ProjectView; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.undo.DocumentReferenceManager; +import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -47,7 +49,7 @@ public class StudySubtaskUtils { int fromSubtaskIndex = task.getActiveSubtaskIndex(); for (Map.Entry entry : task.getTaskFiles().entrySet()) { String name = entry.getKey(); - VirtualFile virtualFile = taskDir.findChild(name); + VirtualFile virtualFile = taskDir.findFileByRelativePath(name); if (virtualFile == null) { continue; } @@ -56,7 +58,8 @@ public class StudySubtaskUtils { if (document == null) { continue; } - updatePlaceholderTexts(project, document, taskFile, fromSubtaskIndex, toSubtaskIndex); + updatePlaceholderTexts(document, taskFile, fromSubtaskIndex, toSubtaskIndex); + UndoManager.getInstance(project).nonundoableActionPerformed(DocumentReferenceManager.getInstance().create(document), false); EditorNotifications.getInstance(project).updateNotifications(virtualFile); if (StudyUtils.isStudentProject(project)) { WolfTheProblemSolver.getInstance(project).clearProblems(virtualFile); @@ -112,22 +115,21 @@ public class StudySubtaskUtils { } } - private static void updatePlaceholderTexts(@NotNull Project project, - @NotNull Document document, + private static void updatePlaceholderTexts(@NotNull Document document, @NotNull TaskFile taskFile, int fromSubtaskIndex, int toSubtaskIndex) { taskFile.setTrackLengths(false); for (AnswerPlaceholder placeholder : taskFile.getAnswerPlaceholders()) { - placeholder.switchSubtask(project, document, fromSubtaskIndex, toSubtaskIndex); + placeholder.switchSubtask(document, fromSubtaskIndex, toSubtaskIndex); } taskFile.setTrackLengths(true); } - public static void refreshPlaceholder(@NotNull Project project, @NotNull Editor editor, @NotNull AnswerPlaceholder placeholder) { + public static void refreshPlaceholder(@NotNull Editor editor, @NotNull AnswerPlaceholder placeholder) { int prevSubtaskIndex = placeholder.getActiveSubtaskIndex() - 1; AnswerPlaceholderSubtaskInfo info = placeholder.getSubtaskInfos().get(prevSubtaskIndex); String replacementText = info != null ? info.getAnswer() : placeholder.getTaskText(); - EduUtils.replaceAnswerPlaceholder(project, editor.getDocument(), placeholder, placeholder.getRealLength(), replacementText); + EduUtils.replaceAnswerPlaceholder(editor.getDocument(), placeholder, placeholder.getRealLength(), replacementText); } } \ No newline at end of file diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index 5186c3e57d95..960f3acc60d1 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -82,7 +82,6 @@ public class StudyUtils { } private static final Logger LOG = Logger.getInstance(StudyUtils.class.getName()); - private static final String EMPTY_TASK_TEXT = "Please, open any task to see task description"; private static final String ourPrefix = "