diff --git a/build/order.txt b/build/order.txt index 75cfa9c4af0d..65bd2e4078e4 100644 --- a/build/order.txt +++ b/build/order.txt @@ -1345,7 +1345,6 @@ com/intellij/psi/filters/ElementFilter.class:/lib/openapi.jar com/intellij/profile/codeInspection/InspectionProfileManager.class:/lib/idea.jar com/intellij/profile/codeInspection/SeverityProvider.class:/lib/idea.jar com/intellij/profile/ApplicationProfileManager.class:/lib/openapi.jar -com/intellij/profile/ProfileManager.class:/lib/openapi.jar com/intellij/codeInspection/InspectionProfile.class:/lib/openapi.jar com/intellij/profile/Profile.class:/lib/openapi.jar com/intellij/profile/codeInspection/JavaAwareInspectionProfileManager.class:/lib/idea.jar diff --git a/java/execution/impl/src/com/intellij/testIntegration/SelectTestStep.kt b/java/execution/impl/src/com/intellij/testIntegration/SelectTestStep.kt index 0fcb548f9bf0..95c6d40205c1 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/SelectTestStep.kt +++ b/java/execution/impl/src/com/intellij/testIntegration/SelectTestStep.kt @@ -31,6 +31,7 @@ import javax.swing.AbstractAction import javax.swing.Icon import javax.swing.KeyStroke + class RecentTestsListPopup(popupStep: ListPopupStep, private val testRunner: RecentTestRunner, private val locator: TestLocator) : ListPopupImpl(popupStep) { @@ -50,56 +51,13 @@ class RecentTestsListPopup(popupStep: ListPopupStep, } private fun registerActions(popup: WizardPopup) { - popup.registerAction("alternate", KeyStroke.getKeyStroke("shift pressed SHIFT"), object : AbstractAction() { - override fun actionPerformed(e: ActionEvent) { - shiftPressed() - } - }) + popup.onShiftPressed { shiftPressed() } + popup.onShiftReleased { shiftReleased() } - popup.registerAction("restoreDefault", KeyStroke.getKeyStroke("released SHIFT"), object : AbstractAction() { - override fun actionPerformed(e: ActionEvent) { - shiftReleased() - } - }) - - popup.registerAction("invokeAction", KeyStroke.getKeyStroke("shift ENTER"), object : AbstractAction() { - override fun actionPerformed(e: ActionEvent) { - handleSelect(true) - } - }) - - popup.registerAction("navigate", KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0), object : AbstractAction() { - override fun actionPerformed(e: ActionEvent) { - val values = selectedValues - if (values.size == 1) { - val entry = values[0] as RecentTestsPopupEntry - getElement(entry)?.let { - cancel() - PsiNavigateUtil.navigate(it) - } - } - } - }) - } - - private fun getElement(entry: RecentTestsPopupEntry): PsiElement? { - var element: PsiElement? = null - entry.accept(object : TestEntryVisitor() { - override fun visitTest(test: SingleTestEntry) { - element = locator.getLocation(test.url)?.psiElement - } - - override fun visitSuite(suite: SuiteEntry) { - element = locator.getLocation(suite.suiteUrl)?.psiElement - } - - override fun visitRunConfiguration(configuration: RunConfigurationEntry) { - if (configuration.suites.size == 1) { - visitSuite(configuration.suites[0]) - } - } - }) - return element + if (popup is ListPopupImpl) { + popup.selectOnShiftEnter() + popup.navigateOnF4(locator, this) + } } private fun shiftPressed() { @@ -180,4 +138,64 @@ class SelectConfigurationStep(items: List, return null } +} + + +private fun WizardPopup.onShiftPressed(action: () -> Unit) { + registerAction("alternate", KeyStroke.getKeyStroke("shift pressed SHIFT"), object : AbstractAction() { + override fun actionPerformed(e: ActionEvent) { + action() + } + }) +} + +private fun WizardPopup.onShiftReleased(action: () -> Unit) { + registerAction("restoreDefault", KeyStroke.getKeyStroke("released SHIFT"), object : AbstractAction() { + override fun actionPerformed(e: ActionEvent) { + action() + } + }) +} + +private fun ListPopupImpl.selectOnShiftEnter() { + registerAction("invokeAction", KeyStroke.getKeyStroke("shift ENTER"), object : AbstractAction() { + override fun actionPerformed(e: ActionEvent) { + handleSelect(true) + } + }) +} + +private fun ListPopupImpl.navigateOnF4(locator: TestLocator, parentPopup: RecentTestsListPopup) { + registerAction("navigate", KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0), object : AbstractAction() { + override fun actionPerformed(e: ActionEvent) { + val values = selectedValues + if (values.size == 1) { + val entry = values[0] as RecentTestsPopupEntry + locator.getNavigatableElement(entry)?.let { + parentPopup.cancel() + PsiNavigateUtil.navigate(it) + } + } + } + }) +} + +private fun TestLocator.getNavigatableElement(entry: RecentTestsPopupEntry): PsiElement? { + var element: PsiElement? = null + entry.accept(object : TestEntryVisitor() { + override fun visitTest(test: SingleTestEntry) { + element = getLocation(test.url)?.psiElement + } + + override fun visitSuite(suite: SuiteEntry) { + element = getLocation(suite.suiteUrl)?.psiElement + } + + override fun visitRunConfiguration(configuration: RunConfigurationEntry) { + if (configuration.suites.size == 1) { + visitSuite(configuration.suites[0]) + } + } + }) + return element } \ No newline at end of file diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java index 2a001f46e31a..4509e0aff2d2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java @@ -16,21 +16,21 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInsight.NullableNotNullManager; -import com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint; +import com.intellij.lang.ASTNode; +import com.intellij.lang.TreeBackedLighterAST; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.RecursionManager; -import com.intellij.psi.*; -import com.intellij.psi.tree.IElementType; +import com.intellij.psi.PsiCodeBlock; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiPrimitiveType; +import com.intellij.psi.PsiType; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.util.PsiUtil; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.JBIterable; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -50,31 +50,43 @@ public class ContractInference { } return CachedValuesManager.getCachedValue(method, () -> { - List preContracts = new ContractInferenceInterpreter(method).inferContracts(); - List result = RecursionManager.doPreventingRecursion(method, true, () -> postProcessContracts(method, preContracts)); + TreeBackedLighterAST tree = new TreeBackedLighterAST(method.getContainingFile().getNode()); + PsiCodeBlock body = method.getBody(); + assert body != null; + ASTNode methodNode = method.getNode(); + ASTNode bodyNode = body.getNode(); + List preContracts = methodNode == null || bodyNode == null ? Collections.emptyList() : + new ContractInferenceInterpreter(tree, TreeBackedLighterAST.wrap(methodNode), TreeBackedLighterAST.wrap(bodyNode)).inferContracts(); + List result = RecursionManager.doPreventingRecursion(method, true, () -> postProcessContracts(method, body, preContracts)); if (result == null) result = Collections.emptyList(); return CachedValueProvider.Result.create(result, method, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); }); } @NotNull - private static List postProcessContracts(PsiMethod myMethod, List rawContracts) { - List contracts = ContainerUtil.concat(rawContracts, c -> c.toContracts(myMethod)); + private static List postProcessContracts(@NotNull PsiMethod method, @NotNull PsiCodeBlock body, List rawContracts) { + List contracts = ContainerUtil.concat(rawContracts, c -> c.toContracts(method, body)); if (contracts.isEmpty()) return Collections.emptyList(); - final PsiType returnType = myMethod.getReturnType(); + final PsiType returnType = method.getReturnType(); if (returnType != null && !(returnType instanceof PsiPrimitiveType)) { contracts = boxReturnValues(contracts); } List compatible = ContainerUtil.filter(contracts, contract -> { + for (int i = 0; i < contract.arguments.length; i++) { + if (contract.arguments[i] == NULL_VALUE && NullableNotNullManager.isNotNull(method.getParameterList().getParameters()[i])) { + return false; + } + } + if ((contract.returnValue == NOT_NULL_VALUE || contract.returnValue == NULL_VALUE) && - NullableNotNullManager.getInstance(myMethod.getProject()).isNotNull(myMethod, false)) { + NullableNotNullManager.getInstance(method.getProject()).isNotNull(method, false)) { return false; } return InferenceFromSourceUtil.isReturnTypeCompatible(returnType, contract.returnValue); }); if (compatible.size() > MAX_CONTRACT_COUNT) { - LOG.debug("Too many contracts for " + PsiUtil.getMemberQualifiedName(myMethod) + ", shrinking the list"); + LOG.debug("Too many contracts for " + PsiUtil.getMemberQualifiedName(method) + ", shrinking the list"); return compatible.subList(0, MAX_CONTRACT_COUNT); } return compatible; @@ -90,341 +102,4 @@ public class ContractInference { }); } -} - -class ContractInferenceInterpreter { - private final PsiMethod myMethod; - private final ValueConstraint[] myEmptyConstraints; - - public ContractInferenceInterpreter(PsiMethod method) { - myMethod = method; - myEmptyConstraints = MethodContract.createConstraintArray(myMethod.getParameterList().getParametersCount()); - } - - List inferContracts() { - PsiCodeBlock body = myMethod.getBody(); - PsiStatement[] statements = body == null ? PsiStatement.EMPTY_ARRAY : body.getStatements(); - if (statements.length == 0) return Collections.emptyList(); - - if (statements.length == 1) { - if (statements[0] instanceof PsiReturnStatement) { - List result = handleDelegation(((PsiReturnStatement)statements[0]).getReturnValue(), false); - if (result != null) { - return result; - } - } - else if (statements[0] instanceof PsiExpressionStatement && ((PsiExpressionStatement)statements[0]).getExpression() instanceof PsiMethodCallExpression) { - List result = handleDelegation(((PsiExpressionStatement)statements[0]).getExpression(), false); - if (result != null) return result; - } - } - - return visitStatements(Collections.singletonList(myEmptyConstraints), statements); - } - - @Nullable - private static List handleDelegation(final PsiExpression expression, final boolean negated) { - if (expression instanceof PsiParenthesizedExpression) { - return handleDelegation(((PsiParenthesizedExpression)expression).getExpression(), negated); - } - - if (expression instanceof PsiPrefixExpression && ((PsiPrefixExpression)expression).getOperationTokenType() == JavaTokenType.EXCL) { - return handleDelegation(((PsiPrefixExpression)expression).getOperand(), !negated); - } - - if (expression instanceof PsiMethodCallExpression) { - return Collections.singletonList(new DelegationContract((PsiMethodCallExpression)expression, negated)); - } - - return null; - } - - @NotNull - private List visitExpression(final List states, @Nullable PsiExpression expr) { - if (states.isEmpty()) return Collections.emptyList(); - if (states.size() > 300) return Collections.emptyList(); // too complex - - if (expr instanceof PsiPolyadicExpression) { - PsiExpression[] operands = ((PsiPolyadicExpression)expr).getOperands(); - IElementType op = ((PsiPolyadicExpression)expr).getOperationTokenType(); - if (operands.length == 2 && (op == JavaTokenType.EQEQ || op == JavaTokenType.NE)) { - return asPreContracts(visitEqualityComparison(states, operands[0], operands[1], op == JavaTokenType.EQEQ)); - } - if (op == JavaTokenType.ANDAND || op == JavaTokenType.OROR) { - return asPreContracts(visitLogicalOperation(operands, op == JavaTokenType.ANDAND, states)); - } - } - - if (expr instanceof PsiConditionalExpression) { - List conditionResults = visitExpression(states, ((PsiConditionalExpression)expr).getCondition()); - return ContainerUtil.concat( - visitExpression(antecedentsReturning(conditionResults, TRUE_VALUE), ((PsiConditionalExpression)expr).getThenExpression()), - visitExpression(antecedentsReturning(conditionResults, FALSE_VALUE), ((PsiConditionalExpression)expr).getElseExpression())); - } - - - if (expr instanceof PsiParenthesizedExpression) { - return visitExpression(states, ((PsiParenthesizedExpression)expr).getExpression()); - } - if (expr instanceof PsiTypeCastExpression) { - return visitExpression(states, ((PsiTypeCastExpression)expr).getOperand()); - } - - if (expr instanceof PsiPrefixExpression && ((PsiPrefixExpression)expr).getOperationTokenType() == JavaTokenType.EXCL) { - List result = ContainerUtil.newArrayList(); - for (PreContract contract : visitExpression(states, ((PsiPrefixExpression)expr).getOperand())) { - ContainerUtil.addIfNotNull(result, NegatingContract.negate(contract)); - } - return result; - } - - if (expr instanceof PsiInstanceOfExpression) { - final int parameter = resolveParameter(((PsiInstanceOfExpression)expr).getOperand()); - if (parameter >= 0) { - return asPreContracts(ContainerUtil.mapNotNull(states, state -> contractWithConstraint(state, parameter, NULL_VALUE, FALSE_VALUE))); - } - } - - if (expr instanceof PsiNewExpression) { - return asPreContracts(toContracts(states, NOT_NULL_VALUE)); - } - if (expr instanceof PsiMethodCallExpression) { - return Collections.singletonList(new MethodCallContract((PsiMethodCallExpression)expr, states)); - } - - final ValueConstraint constraint = getLiteralConstraint(expr); - if (constraint != null) { - return asPreContracts(toContracts(states, constraint)); - } - - int paramIndex = resolveParameter(expr); - if (paramIndex >= 0) { - List result = ContainerUtil.newArrayList(); - for (ValueConstraint[] state : states) { - if (state[paramIndex] != ANY_VALUE) { - // the second 'o' reference in cases like: if (o != null) return o; - result.add(new MethodContract(state, state[paramIndex])); - } else if (textMatches(getParameter(paramIndex).getTypeElement(), PsiKeyword.BOOLEAN)) { - // if (boolValue) ... - ContainerUtil.addIfNotNull(result, contractWithConstraint(state, paramIndex, TRUE_VALUE, TRUE_VALUE)); - ContainerUtil.addIfNotNull(result, contractWithConstraint(state, paramIndex, FALSE_VALUE, FALSE_VALUE)); - } - } - return asPreContracts(result); - } - - return Collections.emptyList(); - } - - @NotNull - private static List asPreContracts(List contracts) { - return ContainerUtil.map(contracts, KnownContract::new); - } - - @Nullable - private MethodContract contractWithConstraint(ValueConstraint[] state, - int parameter, ValueConstraint paramConstraint, - ValueConstraint returnValue) { - ValueConstraint[] newState = withConstraint(state, parameter, paramConstraint, myMethod); - return newState == null ? null : new MethodContract(newState, returnValue); - } - - private static boolean textMatches(@Nullable PsiTypeElement typeElement, @NotNull String text) { - return typeElement != null && typeElement.textMatches(text); - } - - private List visitEqualityComparison(List states, - PsiExpression op1, - PsiExpression op2, - boolean equality) { - int parameter = resolveParameter(op1); - ValueConstraint constraint = getLiteralConstraint(op2); - if (parameter < 0 || constraint == null) { - parameter = resolveParameter(op2); - constraint = getLiteralConstraint(op1); - } - if (parameter >= 0 && constraint != null) { - List result = ContainerUtil.newArrayList(); - for (ValueConstraint[] state : states) { - if (constraint == NOT_NULL_VALUE) { - if (!(getParameter(parameter).getType() instanceof PsiPrimitiveType)) { - ContainerUtil.addIfNotNull(result, contractWithConstraint(state, parameter, NULL_VALUE, equality ? FALSE_VALUE : TRUE_VALUE)); - } - } else { - ContainerUtil.addIfNotNull(result, contractWithConstraint(state, parameter, constraint, equality ? TRUE_VALUE : FALSE_VALUE)); - ContainerUtil.addIfNotNull(result, contractWithConstraint(state, parameter, negateConstraint(constraint), - equality ? FALSE_VALUE : TRUE_VALUE)); - } - } - return result; - } - return Collections.emptyList(); - } - - private PsiParameter getParameter(int parameter) { - return getParameter(parameter, myMethod); - } - - private static PsiParameter getParameter(int parameter, PsiMethod method) { - return method.getParameterList().getParameters()[parameter]; - } - - static List toContracts(List states, ValueConstraint constraint) { - return ContainerUtil.map(states, state -> new MethodContract(state, constraint)); - } - - private List visitLogicalOperation(PsiExpression[] operands, boolean conjunction, List states) { - ValueConstraint breakValue = conjunction ? FALSE_VALUE : TRUE_VALUE; - List finalStates = ContainerUtil.newArrayList(); - for (PsiExpression operand : operands) { - List opResults = visitExpression(states, operand); - finalStates.addAll(ContainerUtil.filter(knownContracts(opResults), contract -> contract.returnValue == breakValue)); - states = antecedentsReturning(opResults, negateConstraint(breakValue)); - } - finalStates.addAll(toContracts(states, negateConstraint(breakValue))); - return finalStates; - } - - private static List knownContracts(List values) { - return ContainerUtil.mapNotNull(values, pc -> pc instanceof KnownContract ? ((KnownContract)pc).getContract() : null); - } - - private static List antecedentsReturning(List values, ValueConstraint result) { - return ContainerUtil.mapNotNull(knownContracts(values), contract -> contract.returnValue == result ? contract.arguments : null); - } - - private static class CodeBlockContracts { - List accumulated = new ArrayList<>(); - List declarations = new ArrayList<>(); - - void addAll(List contracts) { - if (contracts.isEmpty()) return; - - if (declarations.isEmpty()) { - accumulated.addAll(contracts); - } else { - accumulated.add(new SideEffectFilter(getVariableInitializers(), contracts)); - } - } - - @NotNull - List getVariableInitializers() { - return JBIterable.from(declarations). - flatMap(s -> JBIterable.of(s.getDeclaredElements())). - filter(PsiVariable.class). - flatMap(var -> JBIterable.of(var.getInitializer())). - toList(); - } - } - - @NotNull - private List visitStatements(List states, PsiStatement... statements) { - CodeBlockContracts result = new CodeBlockContracts(); - for (PsiStatement statement : statements) { - if (statement instanceof PsiBlockStatement) { - result.addAll(visitStatements(states, ((PsiBlockStatement)statement).getCodeBlock().getStatements())); - } - else if (statement instanceof PsiIfStatement) { - List conditionResults = visitExpression(states, ((PsiIfStatement)statement).getCondition()); - - PsiStatement thenBranch = ((PsiIfStatement)statement).getThenBranch(); - if (thenBranch != null) { - result.addAll(visitStatements(antecedentsReturning(conditionResults, TRUE_VALUE), thenBranch)); - } - - List falseStates = antecedentsReturning(conditionResults, FALSE_VALUE); - PsiStatement elseBranch = ((PsiIfStatement)statement).getElseBranch(); - if (elseBranch != null) { - result.addAll(visitStatements(falseStates, elseBranch)); - } else { - states = falseStates; - continue; - } - } - else if (statement instanceof PsiWhileStatement) { - states = antecedentsReturning(visitExpression(states, ((PsiWhileStatement)statement).getCondition()), FALSE_VALUE); - continue; - } - else if (statement instanceof PsiThrowStatement) { - result.addAll(asPreContracts(toContracts(states, THROW_EXCEPTION))); - } - else if (statement instanceof PsiReturnStatement) { - result.addAll(visitExpression(states, ((PsiReturnStatement)statement).getReturnValue())); - } - else if (statement instanceof PsiAssertStatement) { - List conditionResults = visitExpression(states, ((PsiAssertStatement)statement).getAssertCondition()); - result.addAll(asPreContracts(toContracts(antecedentsReturning(conditionResults, FALSE_VALUE), THROW_EXCEPTION))); - } - else if (statement instanceof PsiDeclarationStatement) { - result.declarations.add((PsiDeclarationStatement)statement); - continue; - } - else if (statement instanceof PsiDoWhileStatement) { - result.addAll(visitStatements(states, ((PsiDoWhileStatement)statement).getBody())); - } - - break; // visit only the first statement unless it's 'if' whose 'then' always returns and the next statement is effectively 'else' - } - return result.accumulated; - } - - @Nullable - static ValueConstraint getLiteralConstraint(@Nullable PsiExpression expr) { - if (expr instanceof PsiLiteralExpression) { - if (expr.textMatches(PsiKeyword.TRUE)) return TRUE_VALUE; - if (expr.textMatches(PsiKeyword.FALSE)) return FALSE_VALUE; - if (expr.textMatches(PsiKeyword.NULL)) return NULL_VALUE; - return NOT_NULL_VALUE; - } - return null; - } - - static ValueConstraint negateConstraint(@NotNull ValueConstraint constraint) { - //noinspection EnumSwitchStatementWhichMissesCases - switch (constraint) { - case NULL_VALUE: return NOT_NULL_VALUE; - case NOT_NULL_VALUE: return NULL_VALUE; - case TRUE_VALUE: return FALSE_VALUE; - case FALSE_VALUE: return TRUE_VALUE; - } - return constraint; - } - - private int resolveParameter(@Nullable PsiExpression expr) { - return resolveParameter(expr, myMethod); - } - - static int resolveParameter(@Nullable PsiExpression expr, PsiMethod method) { - if (expr instanceof PsiReferenceExpression && !((PsiReferenceExpression)expr).isQualified()) { - String name = ((PsiReferenceExpression)expr).getReferenceName(); - if (name == null) return -1; - - PsiParameter[] parameters = method.getParameterList().getParameters(); - for (int i = 0; i < parameters.length; i++) { - if (name.equals(parameters[i].getName())) { - return i; - } - } - } - return -1; - } - - @Nullable - static ValueConstraint[] withConstraint(ValueConstraint[] constraints, int index, ValueConstraint constraint, PsiMethod method) { - if (constraints[index] == constraint) return constraints; - - ValueConstraint negated = negateConstraint(constraint); - if (negated != constraint && constraints[index] == negated) { - return null; - } - - if (constraint == NULL_VALUE && NullableNotNullManager.isNotNull(getParameter(index, method))) { - return null; - } - - ValueConstraint[] copy = constraints.clone(); - copy[index] = constraint; - return copy; - } - } \ No newline at end of file diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInferenceInterpreter.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInferenceInterpreter.java new file mode 100644 index 000000000000..2f78283ac76b --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInferenceInterpreter.java @@ -0,0 +1,396 @@ +/* + * 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.codeInspection.dataFlow; + +import com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint; +import com.intellij.lang.LighterAST; +import com.intellij.lang.LighterASTNode; +import com.intellij.psi.JavaTokenType; +import com.intellij.psi.impl.source.JavaLightTreeUtil; +import com.intellij.psi.impl.source.tree.ElementType; +import com.intellij.psi.tree.IElementType; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint.*; +import static com.intellij.psi.impl.source.JavaLightTreeUtil.findExpressionChild; +import static com.intellij.psi.impl.source.JavaLightTreeUtil.getExpressionChildren; +import static com.intellij.psi.impl.source.tree.JavaElementType.*; +import static com.intellij.psi.impl.source.tree.LightTreeUtil.firstChildOfType; +import static com.intellij.psi.impl.source.tree.LightTreeUtil.getChildrenOfType; + +class ContractInferenceInterpreter { + private final LighterAST myTree; + private final LighterASTNode myMethod; + private final LighterASTNode myBody; + + public ContractInferenceInterpreter(LighterAST tree, LighterASTNode method, LighterASTNode body) { + myTree = tree; + myMethod = method; + myBody = body; + } + + @NotNull + private List getParameters() { + LighterASTNode paramList = firstChildOfType(myTree, myMethod, PARAMETER_LIST); + return paramList != null ? getChildrenOfType(myTree, paramList, PARAMETER) : Collections.emptyList(); + } + + List inferContracts() { + LighterASTNode[] statements = getStatements(myBody); + if (statements.length == 0) return Collections.emptyList(); + + if (statements.length == 1) { + if (statements[0].getTokenType() == RETURN_STATEMENT) { + List result = handleDelegation(findExpressionChild(myTree, statements[0]), false); + if (result != null) { + return result; + } + } + else if (statements[0].getTokenType() == EXPRESSION_STATEMENT) { + LighterASTNode expr = findExpressionChild(myTree, statements[0]); + List result = expr != null && expr.getTokenType() == METHOD_CALL_EXPRESSION ? handleDelegation(expr, false) : null; + if (result != null) return result; + } + } + + return visitStatements(Collections.singletonList(MethodContract.createConstraintArray(getParameters().size())), statements); + } + + @Nullable + private LighterASTNode getCodeBlock(@Nullable LighterASTNode parent) { + return firstChildOfType(myTree, parent, CODE_BLOCK); + } + + @NotNull + private LighterASTNode[] getStatements(@Nullable LighterASTNode codeBlock) { + return codeBlock == null + ? LighterASTNode.EMPTY_ARRAY + : getChildrenOfType(myTree, codeBlock, ElementType.JAVA_STATEMENT_BIT_SET).toArray(LighterASTNode.EMPTY_ARRAY); + } + + @Nullable + private List handleDelegation(@Nullable LighterASTNode expression, boolean negated) { + if (expression == null) return null; + if (expression.getTokenType() == PARENTH_EXPRESSION) { + return handleDelegation(findExpressionChild(myTree, expression), negated); + } + + if (isNegationExpression(expression)) { + return handleDelegation(findExpressionChild(myTree, expression), !negated); + } + + if (expression.getTokenType() == METHOD_CALL_EXPRESSION) { + return Collections.singletonList(new DelegationContract(ExpressionRange.create(expression, myBody.getStartOffset()), negated)); + } + + return null; + } + + private boolean isNegationExpression(@Nullable LighterASTNode expression) { + return expression != null && expression.getTokenType() == PREFIX_EXPRESSION && firstChildOfType(myTree, expression, JavaTokenType.EXCL) != null; + } + + @NotNull + private List visitExpression(final List states, @Nullable LighterASTNode expr) { + if (expr == null) return Collections.emptyList(); + if (states.isEmpty()) return Collections.emptyList(); + if (states.size() > 300) return Collections.emptyList(); // too complex + + IElementType type = expr.getTokenType(); + if (type == POLYADIC_EXPRESSION || type == BINARY_EXPRESSION) { + List operands = getExpressionChildren(myTree, expr); + if (operands.size() == 2) { + boolean equality = firstChildOfType(myTree, expr, JavaTokenType.EQEQ) != null; + if (equality || firstChildOfType(myTree, expr, JavaTokenType.NE) != null) { + return asPreContracts(visitEqualityComparison(states, operands.get(0), operands.get(1), equality)); + } + } + boolean logicalAnd = firstChildOfType(myTree, expr, JavaTokenType.ANDAND) != null; + if (logicalAnd || firstChildOfType(myTree, expr, JavaTokenType.OROR) != null) { + return asPreContracts(visitLogicalOperation(operands, logicalAnd, states)); + } + } + + if (type == CONDITIONAL_EXPRESSION) { + List children = getExpressionChildren(myTree, expr); + if (children.size() != 3) return Collections.emptyList(); + + List conditionResults = visitExpression(states, children.get(0)); + return ContainerUtil.concat( + visitExpression(antecedentsReturning(conditionResults, TRUE_VALUE), children.get(1)), + visitExpression(antecedentsReturning(conditionResults, FALSE_VALUE), children.get(2))); + } + + + if (type == PARENTH_EXPRESSION) { + return visitExpression(states, findExpressionChild(myTree, expr)); + } + if (type == TYPE_CAST_EXPRESSION) { + return visitExpression(states, findExpressionChild(myTree, expr)); + } + + if (isNegationExpression(expr)) { + return ContainerUtil.mapNotNull(visitExpression(states, findExpressionChild(myTree, expr)), PreContract::negate); + } + + if (type == INSTANCE_OF_EXPRESSION) { + final int parameter = resolveParameter(findExpressionChild(myTree, expr)); + if (parameter >= 0) { + return asPreContracts(ContainerUtil.mapNotNull(states, state -> contractWithConstraint(state, parameter, NULL_VALUE, FALSE_VALUE))); + } + } + + if (type == NEW_EXPRESSION) { + return asPreContracts(toContracts(states, NOT_NULL_VALUE)); + } + if (type == METHOD_CALL_EXPRESSION) { + return Collections.singletonList(new MethodCallContract(ExpressionRange.create(expr, myBody.getStartOffset()), states)); + } + + final ValueConstraint constraint = getLiteralConstraint(expr); + if (constraint != null) { + return asPreContracts(toContracts(states, constraint)); + } + + int paramIndex = resolveParameter(expr); + if (paramIndex >= 0) { + List result = ContainerUtil.newArrayList(); + for (ValueConstraint[] state : states) { + if (state[paramIndex] != ANY_VALUE) { + // the second 'o' reference in cases like: if (o != null) return o; + result.add(new MethodContract(state, state[paramIndex])); + } else if (JavaTokenType.BOOLEAN_KEYWORD == getPrimitiveParameterType(paramIndex)) { + // if (boolValue) ... + ContainerUtil.addIfNotNull(result, contractWithConstraint(state, paramIndex, TRUE_VALUE, TRUE_VALUE)); + ContainerUtil.addIfNotNull(result, contractWithConstraint(state, paramIndex, FALSE_VALUE, FALSE_VALUE)); + } + } + return asPreContracts(result); + } + + return Collections.emptyList(); + } + + @NotNull + private static List asPreContracts(List contracts) { + return ContainerUtil.map(contracts, KnownContract::new); + } + + @Nullable + private static MethodContract contractWithConstraint(ValueConstraint[] state, + int parameter, ValueConstraint paramConstraint, + ValueConstraint returnValue) { + ValueConstraint[] newState = withConstraint(state, parameter, paramConstraint); + return newState == null ? null : new MethodContract(newState, returnValue); + } + + private List visitEqualityComparison(List states, + LighterASTNode op1, + LighterASTNode op2, + boolean equality) { + int parameter = resolveParameter(op1); + ValueConstraint constraint = getLiteralConstraint(op2); + if (parameter < 0 || constraint == null) { + parameter = resolveParameter(op2); + constraint = getLiteralConstraint(op1); + } + if (parameter >= 0 && constraint != null) { + List result = ContainerUtil.newArrayList(); + for (ValueConstraint[] state : states) { + if (constraint == NOT_NULL_VALUE) { + if (getPrimitiveParameterType(parameter) == null) { + ContainerUtil.addIfNotNull(result, contractWithConstraint(state, parameter, NULL_VALUE, equality ? FALSE_VALUE : TRUE_VALUE)); + } + } else { + ContainerUtil.addIfNotNull(result, contractWithConstraint(state, parameter, constraint, equality ? TRUE_VALUE : FALSE_VALUE)); + ContainerUtil.addIfNotNull(result, contractWithConstraint(state, parameter, negateConstraint(constraint), + equality ? FALSE_VALUE : TRUE_VALUE)); + } + } + return result; + } + return Collections.emptyList(); + } + + @Nullable + private IElementType getPrimitiveParameterType(int paramIndex) { + LighterASTNode typeElement = firstChildOfType(myTree, getParameters().get(paramIndex), TYPE); + LighterASTNode primitive = firstChildOfType(myTree, typeElement, ElementType.PRIMITIVE_TYPE_BIT_SET); + return primitive == null ? null : primitive.getTokenType(); + } + + static List toContracts(List states, ValueConstraint constraint) { + return ContainerUtil.map(states, state -> new MethodContract(state, constraint)); + } + + private List visitLogicalOperation(List operands, boolean conjunction, List states) { + ValueConstraint breakValue = conjunction ? FALSE_VALUE : TRUE_VALUE; + List finalStates = ContainerUtil.newArrayList(); + for (LighterASTNode operand : operands) { + List opResults = visitExpression(states, operand); + finalStates.addAll(ContainerUtil.filter(knownContracts(opResults), contract -> contract.returnValue == breakValue)); + states = antecedentsReturning(opResults, negateConstraint(breakValue)); + } + finalStates.addAll(toContracts(states, negateConstraint(breakValue))); + return finalStates; + } + + private static List knownContracts(List values) { + return ContainerUtil.mapNotNull(values, pc -> pc instanceof KnownContract ? ((KnownContract)pc).getContract() : null); + } + + private static List antecedentsReturning(List values, ValueConstraint result) { + return ContainerUtil.mapNotNull(knownContracts(values), contract -> contract.returnValue == result ? contract.arguments : null); + } + + private static class CodeBlockContracts { + List accumulated = new ArrayList<>(); + List varInitializers = new ArrayList<>(); + + void addAll(List contracts) { + if (contracts.isEmpty()) return; + + if (varInitializers.isEmpty()) { + accumulated.addAll(contracts); + } else { + accumulated.add(new SideEffectFilter(varInitializers, contracts)); + } + } + + void registerDeclaration(@NotNull LighterASTNode declStatement, @NotNull LighterAST tree, int scopeStart) { + for (LighterASTNode var : getChildrenOfType(tree, declStatement, LOCAL_VARIABLE)) { + LighterASTNode initializer = findExpressionChild(tree, var); + if (initializer != null) { + varInitializers.add(ExpressionRange.create(initializer, scopeStart)); + } + } + } + } + + @NotNull + private List visitStatements(List states, LighterASTNode... statements) { + CodeBlockContracts result = new CodeBlockContracts(); + for (LighterASTNode statement : statements) { + IElementType type = statement.getTokenType(); + if (type == BLOCK_STATEMENT) { + result.addAll(visitStatements(states, getStatements(getCodeBlock(statement)))); + } + else if (type == IF_STATEMENT) { + List conditionResults = visitExpression(states, findExpressionChild(myTree, statement)); + + LighterASTNode[] thenElse = getStatements(statement); + if (thenElse.length > 0) { + result.addAll(visitStatements(antecedentsReturning(conditionResults, TRUE_VALUE), thenElse[0])); + } + + List falseStates = antecedentsReturning(conditionResults, FALSE_VALUE); + if (thenElse.length > 1) { + result.addAll(visitStatements(falseStates, thenElse[1])); + } else { + states = falseStates; + continue; + } + } + else if (type == WHILE_STATEMENT) { + states = antecedentsReturning(visitExpression(states, findExpressionChild(myTree, statement)), FALSE_VALUE); + continue; + } + else if (type == THROW_STATEMENT) { + result.addAll(asPreContracts(toContracts(states, THROW_EXCEPTION))); + } + else if (type == RETURN_STATEMENT) { + result.addAll(visitExpression(states, findExpressionChild(myTree, statement))); + } + else if (type == ASSERT_STATEMENT) { + List conditionResults = visitExpression(states, findExpressionChild(myTree, statement)); + result.addAll(asPreContracts(toContracts(antecedentsReturning(conditionResults, FALSE_VALUE), THROW_EXCEPTION))); + } + else if (type == DECLARATION_STATEMENT) { + result.registerDeclaration(statement, myTree, myBody.getStartOffset()); + continue; + } + else if (type == DO_WHILE_STATEMENT) { + result.addAll(visitStatements(states, getStatements(statement))); + } + + break; // visit only the first statement unless it's 'if' whose 'then' always returns and the next statement is effectively 'else' + } + return result.accumulated; + } + + @Nullable + private ValueConstraint getLiteralConstraint(@Nullable LighterASTNode expr) { + if (expr != null && expr.getTokenType() == LITERAL_EXPRESSION) { + return getLiteralConstraint(myTree.getChildren(expr).get(0).getTokenType()); + } + return null; + } + + @NotNull + static ValueConstraint getLiteralConstraint(@NotNull IElementType literalTokenType) { + if (literalTokenType.equals(JavaTokenType.TRUE_KEYWORD)) return TRUE_VALUE; + if (literalTokenType.equals(JavaTokenType.FALSE_KEYWORD)) return FALSE_VALUE; + if (literalTokenType.equals(JavaTokenType.NULL_KEYWORD)) return NULL_VALUE; + return NOT_NULL_VALUE; + } + + static ValueConstraint negateConstraint(@NotNull ValueConstraint constraint) { + //noinspection EnumSwitchStatementWhichMissesCases + switch (constraint) { + case NULL_VALUE: return NOT_NULL_VALUE; + case NOT_NULL_VALUE: return NULL_VALUE; + case TRUE_VALUE: return FALSE_VALUE; + case FALSE_VALUE: return TRUE_VALUE; + } + return constraint; + } + + private int resolveParameter(@Nullable LighterASTNode expr) { + if (expr != null && expr.getTokenType() == REFERENCE_EXPRESSION && findExpressionChild(myTree, expr) == null) { + String name = JavaLightTreeUtil.getNameIdentifierText(myTree, expr); + if (name == null) return -1; + + List parameters = getParameters(); + for (int i = 0; i < parameters.size(); i++) { + if (name.equals(JavaLightTreeUtil.getNameIdentifierText(myTree, parameters.get(i)))) { + return i; + } + } + } + return -1; + } + + @Nullable + static ValueConstraint[] withConstraint(ValueConstraint[] constraints, int index, ValueConstraint constraint) { + if (constraints[index] == constraint) return constraints; + + ValueConstraint negated = negateConstraint(constraint); + if (negated != constraint && constraints[index] == negated) { + return null; + } + + ValueConstraint[] copy = constraints.clone(); + copy[index] = constraint; + return copy; + } + +} \ No newline at end of file diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java index 0f3ba3ae4aec..3d92a10278ae 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/MethodContract.java @@ -18,7 +18,6 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInspection.dataFlow.value.DfaConstValue; import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,6 +36,7 @@ public class MethodContract { this.returnValue = returnValue; } + @NotNull static ValueConstraint[] createConstraintArray(int paramCount) { ValueConstraint[] args = new ValueConstraint[paramCount]; for (int i = 0; i < args.length; i++) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java index 88b292bc4d3c..08493ec1a8f8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInspection.dataFlow; +import com.intellij.lang.ASTNode; import com.intellij.lang.LighterAST; import com.intellij.lang.LighterASTNode; import com.intellij.lang.TreeBackedLighterAST; @@ -54,7 +55,8 @@ public class NullityInference { return CachedValuesManager.getCachedValue(method, () -> { TreeBackedLighterAST tree = new TreeBackedLighterAST(method.getContainingFile().getNode()); PsiCodeBlock body = ObjectUtils.assertNotNull(method.getBody()); - NullityInferenceResult result = doInferNullity(tree, TreeBackedLighterAST.wrap(body.getNode())); + ASTNode node = body.getNode(); + NullityInferenceResult result = node == null ? null : doInferNullity(tree, TreeBackedLighterAST.wrap(node)); Nullness nullness = result == null ? null : RecursionManager.doPreventingRecursion(method, true, () -> result.getNullness(method, body)); if (nullness == null) nullness = Nullness.UNKNOWN; return CachedValueProvider.Result.create(nullness, method, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PreContract.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PreContract.java deleted file mode 100644 index 0bb6cb022f6d..000000000000 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PreContract.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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.codeInspection.dataFlow; - -import com.intellij.codeInsight.NullableNotNullManager; -import com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint; -import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction; -import com.intellij.psi.*; -import com.intellij.util.containers.ContainerUtil; -import com.siyeh.ig.psiutils.SideEffectChecker; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.List; - -import static com.intellij.codeInspection.dataFlow.ContractInferenceInterpreter.*; -import static com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint.*; - -/** - * @author peter - */ -public abstract class PreContract { - - @NotNull - abstract List toContracts(@NotNull PsiMethod method); - -} - -class KnownContract extends PreContract { - private final MethodContract myKnownContract; - - KnownContract(@NotNull MethodContract knownContract) { - myKnownContract = knownContract; - } - - @NotNull - MethodContract getContract() { - return myKnownContract; - } - - @NotNull - @Override - List toContracts(@NotNull PsiMethod method) { - return Collections.singletonList(myKnownContract); - } -} - -class DelegationContract extends PreContract { - - private final PsiMethodCallExpression myExpression; - private final boolean myNegated; - - DelegationContract(PsiMethodCallExpression expression, boolean negated) { - myExpression = expression; - myNegated = negated; - } - - @NotNull - @Override - List toContracts(@NotNull PsiMethod method) { - JavaResolveResult result = myExpression.resolveMethodGenerics(); - - final PsiMethod targetMethod = (PsiMethod)result.getElement(); - if (targetMethod == null) return Collections.emptyList(); - - final PsiParameter[] parameters = targetMethod.getParameterList().getParameters(); - final PsiExpression[] arguments = myExpression.getArgumentList().getExpressions(); - final boolean varArgCall = MethodCallInstruction.isVarArgCall(targetMethod, result.getSubstitutor(), arguments, parameters); - - final boolean notNull = NullableNotNullManager.isNotNull(targetMethod); - ValueConstraint[] emptyConstraints = MethodContract.createConstraintArray(method.getParameterList().getParametersCount()); - List fromDelegate = ContainerUtil.mapNotNull(ControlFlowAnalyzer.getMethodContracts(targetMethod), delegateContract -> { - ValueConstraint[] answer = emptyConstraints; - for (int i = 0; i < delegateContract.arguments.length; i++) { - if (i >= arguments.length) return null; - ValueConstraint argConstraint = delegateContract.arguments[i]; - if (argConstraint != ANY_VALUE) { - if (varArgCall && i >= parameters.length - 1) { - if (argConstraint == NULL_VALUE) { - return null; - } - break; - } - - int paramIndex = resolveParameter(arguments[i], method); - if (paramIndex < 0) { - if (argConstraint != getLiteralConstraint(arguments[i])) { - return null; - } - } - else { - answer = withConstraint(answer, paramIndex, argConstraint, method); - if (answer == null) { - return null; - } - } - } - } - ValueConstraint returnValue = myNegated ? negateConstraint(delegateContract.returnValue) : delegateContract.returnValue; - if (notNull && returnValue != THROW_EXCEPTION) { - returnValue = NOT_NULL_VALUE; - } - return answer == null ? null : new MethodContract(answer, returnValue); - }); - if (notNull) { - return ContainerUtil.concat(fromDelegate, Collections.singletonList(new MethodContract(emptyConstraints, NOT_NULL_VALUE))); - } - return fromDelegate; - } -} - -class SideEffectFilter extends PreContract { - private final List myExpressionsToCheck; - private final List myContracts; - - SideEffectFilter(List expressionsToCheck, List contracts) { - myExpressionsToCheck = expressionsToCheck; - myContracts = contracts; - } - - @NotNull - @Override - List toContracts(@NotNull PsiMethod method) { - if (ContainerUtil.exists(myExpressionsToCheck, d -> SideEffectChecker.mayHaveSideEffects(d))) { - return Collections.emptyList(); - } - return ContainerUtil.concat(myContracts, c -> c.toContracts(method)); - } - -} - -class NegatingContract extends PreContract { - private final PreContract myNegated; - - private NegatingContract(PreContract negated) { - myNegated = negated; - } - - @NotNull - @Override - List toContracts(@NotNull PsiMethod method) { - return ContainerUtil.mapNotNull(myNegated.toContracts(method), NegatingContract::negateContract); - } - - @Nullable - static PreContract negate(@NotNull PreContract contract) { - if (contract instanceof KnownContract) { - MethodContract negated = negateContract(((KnownContract)contract).getContract()); - return negated == null ? null : new KnownContract(negated); - } - return new NegatingContract(contract); - } - - @Nullable - private static MethodContract negateContract(MethodContract c) { - ValueConstraint ret = c.returnValue; - return ret == TRUE_VALUE || ret == FALSE_VALUE ? new MethodContract(c.arguments, negateConstraint(ret)) : null; - } -} - -class MethodCallContract extends PreContract { - private final PsiMethodCallExpression myCall; - private final List myStates; - - MethodCallContract(PsiMethodCallExpression call, List states) { - myCall = call; - myStates = states; - } - - @NotNull - @Override - List toContracts(@NotNull PsiMethod method) { - PsiMethod target = myCall.resolveMethod(); - if (target != null && NullableNotNullManager.isNotNull(target)) { - return ContractInferenceInterpreter.toContracts(myStates, NOT_NULL_VALUE); - } - return Collections.emptyList(); - } -} diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java index cdf7871da9a1..0b8602c287e0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/PurityInference.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInspection.dataFlow; +import com.intellij.lang.ASTNode; import com.intellij.lang.LighterAST; import com.intellij.lang.LighterASTNode; import com.intellij.lang.TreeBackedLighterAST; @@ -57,7 +58,8 @@ public class PurityInference { return CachedValuesManager.getCachedValue(method, () -> { TreeBackedLighterAST tree = new TreeBackedLighterAST(method.getContainingFile().getNode()); PsiCodeBlock body = method.getBody(); - PurityInferenceResult result = doInferPurity(TreeBackedLighterAST.wrap(body.getNode()), tree); + ASTNode node = body.getNode(); + PurityInferenceResult result = node == null ? null : doInferPurity(TreeBackedLighterAST.wrap(node), tree); Boolean pure = RecursionManager.doPreventingRecursion(method, true, () -> result != null && result.isPure(method, body)); return CachedValueProvider.Result.create(pure == Boolean.TRUE, method); }); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inferenceResults.kt b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inferenceResults.kt index ab58349fefc1..fc8c78144ba8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inferenceResults.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inferenceResults.kt @@ -33,7 +33,7 @@ data class ExpressionRange private constructor (private val startOffset: Int, pr fun create(expr: LighterASTNode, scopeStart: Int) = ExpressionRange(expr.startOffset - scopeStart, expr.endOffset - scopeStart) } - internal fun restoreExpression(scope: PsiCodeBlock): PsiExpression? { + fun restoreExpression(scope: PsiCodeBlock): PsiExpression? { val scopeStart = scope.textRange.startOffset return PsiTreeUtil.findElementOfClassAtRange(scope.containingFile, startOffset + scopeStart, endOffset + scopeStart, PsiExpression::class.java) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/preContracts.kt b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/preContracts.kt new file mode 100644 index 000000000000..ed6b52164e61 --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/preContracts.kt @@ -0,0 +1,137 @@ +/* + * 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.codeInspection.dataFlow + +import com.intellij.codeInsight.NullableNotNullManager +import com.intellij.codeInspection.dataFlow.ContractInferenceInterpreter.negateConstraint +import com.intellij.codeInspection.dataFlow.ContractInferenceInterpreter.withConstraint +import com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint.* +import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction +import com.intellij.psi.* +import com.siyeh.ig.psiutils.SideEffectChecker + +/** + * @author peter + */ +interface PreContract { + fun toContracts(method: PsiMethod, body: PsiCodeBlock): List + fun negate(): PreContract? = NegatingContract(this) +} + +internal data class KnownContract(val contract: MethodContract) : PreContract { + override fun toContracts(method: PsiMethod, body: PsiCodeBlock) = listOf(contract) + override fun negate() = negateContract(contract)?.let(::KnownContract) +} + +internal data class DelegationContract(private val expression: ExpressionRange, private val negated: Boolean) : PreContract { + + override fun toContracts(method: PsiMethod, body: PsiCodeBlock): List { + val call = expression.restoreExpression(body) as PsiMethodCallExpression? ?: return emptyList() + + val result = call.resolveMethodGenerics() + val targetMethod = result.element as PsiMethod? ?: return emptyList() + + val parameters = targetMethod.parameterList.parameters + val arguments = call.argumentList.expressions + val varArgCall = MethodCallInstruction.isVarArgCall(targetMethod, result.substitutor, arguments, parameters) + + val fromDelegate = ControlFlowAnalyzer.getMethodContracts(targetMethod).mapNotNull { dc -> + convertDelegatedMethodContract(method, parameters, arguments, varArgCall, dc) + } + if (NullableNotNullManager.isNotNull(targetMethod)) { + return fromDelegate.map { returnNotNull(it) } + listOf(MethodContract(emptyConstraints(method), NOT_NULL_VALUE)) + } + return fromDelegate + } + + private fun convertDelegatedMethodContract(callerMethod: PsiMethod, + targetParameters: Array, + callArguments: Array, + varArgCall: Boolean, + targetContract: MethodContract): MethodContract? { + var answer: Array? = emptyConstraints(callerMethod) + for (i in targetContract.arguments.indices) { + if (i >= callArguments.size) return null + val argConstraint = targetContract.arguments[i] + if (argConstraint != ANY_VALUE) { + if (varArgCall && i >= targetParameters.size - 1) { + if (argConstraint == NULL_VALUE) { + return null + } + break + } + + val argument = callArguments[i] + val paramIndex = resolveParameter(callerMethod, argument) + if (paramIndex >= 0) { + answer = withConstraint(answer, paramIndex, argConstraint) ?: return null + } + else if (argConstraint != getLiteralConstraint(argument)) { + return null + } + } + } + val returnValue = if (negated) negateConstraint(targetContract.returnValue) else targetContract.returnValue + return answer?.let { MethodContract(it, returnValue) } + } + + private fun emptyConstraints(method: PsiMethod) = MethodContract.createConstraintArray(method.parameterList.parametersCount) + + private fun returnNotNull(mc: MethodContract) = if (mc.returnValue == THROW_EXCEPTION) mc else MethodContract(mc.arguments, NOT_NULL_VALUE) + + private fun getLiteralConstraint(argument: PsiExpression) = when (argument) { + is PsiLiteralExpression -> ContractInferenceInterpreter.getLiteralConstraint(argument.getFirstChild().node.elementType) + else -> null + } + + private fun resolveParameter(method: PsiMethod, expr: PsiExpression): Int { + val target = if (expr is PsiReferenceExpression && !expr.isQualified) expr.resolve() else null + return if (target is PsiParameter && target.parent === method.parameterList) method.parameterList.getParameterIndex(target) else -1 + } +} + +internal data class SideEffectFilter(private val expressionsToCheck: List, private val contracts: List) : PreContract { + + override fun toContracts(method: PsiMethod, body: PsiCodeBlock): List { + if (expressionsToCheck.any { d -> mayHaveSideEffects(body, d) }) { + return emptyList() + } + return contracts.flatMap { c -> c.toContracts(method, body) } + } + + private fun mayHaveSideEffects(body: PsiCodeBlock, range: ExpressionRange) = + range.restoreExpression(body)?.let { SideEffectChecker.mayHaveSideEffects(it) } ?: false +} + +internal data class NegatingContract(private val negated: PreContract) : PreContract { + override fun toContracts(method: PsiMethod, body: PsiCodeBlock) = negated.toContracts(method, body).mapNotNull(::negateContract) +} + +private fun negateContract(c: MethodContract): MethodContract? { + val ret = c.returnValue + return if (ret == TRUE_VALUE || ret == FALSE_VALUE) MethodContract(c.arguments, negateConstraint(ret)) else null +} + +internal data class MethodCallContract(private val call: ExpressionRange, private val states: List>) : PreContract { + + override fun toContracts(method: PsiMethod, body: PsiCodeBlock): List { + val target = (call.restoreExpression(body) as PsiMethodCallExpression?)?.resolveMethod() + if (target != null && NullableNotNullManager.isNotNull(target)) { + return ContractInferenceInterpreter.toContracts(states, NOT_NULL_VALUE) + } + return emptyList() + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java index 975f15ccfe43..75d618dd3a19 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/ex/InspectionProfileTest.java @@ -24,8 +24,8 @@ import com.intellij.codeInspection.dataFlow.DataFlowInspection; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase; import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspectionBase; import com.intellij.openapi.util.JDOMUtil; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.profile.Profile; +import com.intellij.profile.codeInspection.BaseInspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; import com.intellij.profile.codeInspection.ui.header.InspectionToolsConfigurable; @@ -68,10 +68,15 @@ public class InspectionProfileTest extends LightIdeaTestCase { finally { //noinspection AssignmentToStaticFieldFromInstanceMethod InspectionProfileImpl.INIT_INSPECTIONS = false; - InspectionProfileManager.getInstance().deleteProfile(PROFILE); + getApplicationProfileManager().deleteProfile(PROFILE); } } + @NotNull + private static BaseInspectionProfileManager getApplicationProfileManager() { + return (BaseInspectionProfileManager)InspectionProfileManager.getInstance(); + } + public void testCopyProjectProfile() throws Exception { final Element element = loadProfile(); final InspectionProfileImpl profile = createProfile(); @@ -82,14 +87,15 @@ public class InspectionProfileTest extends LightIdeaTestCase { } private static InspectionProfileImpl createProfile() { - return new InspectionProfileImpl(PROFILE, InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), InspectionProfileImpl.getBaseProfile(), null); + return new InspectionProfileImpl(PROFILE, InspectionToolRegistrar.getInstance(), InspectionProfileImpl.getBaseProfile()); } + private static InspectionProfileImpl createProfile(@NotNull InspectionProfileImpl base) { - return new InspectionProfileImpl(PROFILE, InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), base, null); + return new InspectionProfileImpl(PROFILE, InspectionToolRegistrar.getInstance(), base); } public void testSameNameSharedProfile() throws Exception { - InspectionProfileManager profileManager = InspectionProfileManager.getInstance(); + BaseInspectionProfileManager profileManager = getApplicationProfileManager(); InspectionProfileImpl localProfile = createProfile(); profileManager.updateProfile(localProfile); @@ -290,7 +296,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { Element toImportElement = profile.writeScheme(); final InspectionProfileImpl importedProfile = - InspectionToolsConfigurable.importInspectionProfile(toImportElement, InspectionProfileManager.getInstance(), getProject(), null); + InspectionToolsConfigurable.importInspectionProfile(toImportElement, getApplicationProfileManager(), getProject(), null); //check merged Element mergedElement = JDOMUtil.loadDocument(mergedText).getRootElement(); @@ -534,13 +540,13 @@ public class InspectionProfileTest extends LightIdeaTestCase { "", serialize(profile)); } - private static String serialize(InspectionProfileImpl profile) throws WriteExternalException { + private static String serialize(InspectionProfileImpl profile) { return JDOMUtil.writeElement(profile.writeScheme()); } private static InspectionProfileImpl createProfile(@NotNull InspectionToolRegistrar registrar) { - InspectionProfileImpl base = new InspectionProfileImpl("Base", registrar, InspectionProfileManager.getInstance(), null, null); - return new InspectionProfileImpl("Foo", registrar, InspectionProfileManager.getInstance(), base, null); + InspectionProfileImpl base = new InspectionProfileImpl("Base", registrar); + return new InspectionProfileImpl("Foo", registrar, base); } public void testGlobalInspectionContext() throws Exception { @@ -579,7 +585,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { } public void testDoNotInstantiateOnSave() throws Exception { - InspectionProfileImpl profile = new InspectionProfileImpl("profile", InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), InspectionProfileImpl.getBaseProfile(), null); + InspectionProfileImpl profile = new InspectionProfileImpl("profile", InspectionToolRegistrar.getInstance(), InspectionProfileImpl.getBaseProfile()); assertEquals(0, countInitializedTools(profile)); InspectionToolWrapper[] toolWrappers = profile.getInspectionTools(null); assertTrue(toolWrappers.length > 0); diff --git a/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfile.java b/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfile.java index b30d399074cb..68d895ab4d31 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfile.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfile.java @@ -35,7 +35,6 @@ import java.util.List; * Date: Dec 7, 2004 */ public interface InspectionProfile extends Profile { - HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey inspectionToolKey, PsiElement element); /** diff --git a/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java b/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java index c800e37f6a89..a1686cf42941 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java @@ -21,6 +21,7 @@ import com.intellij.lang.Language; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.text.StringUtil; @@ -317,7 +318,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool { * @throws InvalidDataException if the loaded data was not valid. */ @SuppressWarnings("deprecation") - public void readSettings(@NotNull Element node) throws InvalidDataException { + public void readSettings(@NotNull Element node) { if (useNewSerializer()) { try { XmlSerializer.deserializeInto(this, node); @@ -327,8 +328,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool { } } else { - //noinspection UnnecessaryFullyQualifiedName - com.intellij.openapi.util.DefaultJDOMExternalizer.readExternal(this, node); + DefaultJDOMExternalizer.readExternal(this, node); } } @@ -340,14 +340,13 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool { * @param node to store settings to. * @throws WriteExternalException if no data should be saved for this component. */ - @SuppressWarnings("deprecation") - public void writeSettings(@NotNull Element node) throws WriteExternalException { + public void writeSettings(@NotNull Element node) { if (useNewSerializer()) { XmlSerializer.serializeInto(this, node, getSerializationFilter()); } else { - //noinspection UnnecessaryFullyQualifiedName - com.intellij.openapi.util.DefaultJDOMExternalizer.writeExternal(this, node); + //noinspection deprecation + DefaultJDOMExternalizer.writeExternal(this, node); } } diff --git a/platform/analysis-api/src/com/intellij/profile/Profile.java b/platform/analysis-api/src/com/intellij/profile/Profile.java index 163875cb8423..db77989742b9 100644 --- a/platform/analysis-api/src/com/intellij/profile/Profile.java +++ b/platform/analysis-api/src/com/intellij/profile/Profile.java @@ -34,9 +34,4 @@ public interface Profile extends Comparable, Scheme { @Override @NotNull String getName(); - - void setProfileManager(@NotNull ProfileManager profileManager); - - @NotNull - ProfileManager getProfileManager(); } diff --git a/platform/analysis-api/src/com/intellij/profile/ProfileManager.java b/platform/analysis-api/src/com/intellij/profile/ProfileManager.java deleted file mode 100644 index 6a982cbb7ea8..000000000000 --- a/platform/analysis-api/src/com/intellij/profile/ProfileManager.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.profile; - -import com.intellij.codeInspection.InspectionProfile; -import com.intellij.openapi.Disposable; -import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -/** - * User: anna - * Date: 09-Dec-2005 - */ -public interface ProfileManager { - default NamedScopesHolder getScopesManager() { - return null; - } - - @NotNull - Collection getProfiles(); - - Profile getProfile(@NotNull String name, boolean returnRootProfileIfNamedIsAbsent); - - default Profile getProfile(@NotNull String name) { - return getProfile(name, true); - } - - void updateProfile(@NotNull Profile profile); - - @NotNull - String[] getAvailableProfileNames(); - - void deleteProfile(@NotNull String name); - - void addProfileChangeListener(@NotNull ProfileChangeAdapter listener, @NotNull Disposable parent); - - @NotNull - InspectionProfile getCurrentProfile(); -} diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java index e63b99ca61ec..d854fb100a66 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java @@ -33,9 +33,9 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.UserDataHolderBase; -import com.intellij.profile.Profile; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; +import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; import com.intellij.psi.*; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.scope.packageSet.NamedScope; @@ -74,7 +74,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G private final StdJobDescriptors myStdJobDescriptors = new StdJobDescriptors(); protected ProgressIndicator myProgressIndicator = new EmptyProgressIndicator(); - private InspectionProfile myExternalProfile; + private InspectionProfileImpl myExternalProfile; protected final Map myExtensions = new HashMap<>(); @@ -107,23 +107,28 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G return (T)myExtensions.get(key); } - public InspectionProfile getCurrentProfile() { - if (myExternalProfile != null) return myExternalProfile; - String currentProfile = ((InspectionManagerBase)InspectionManager.getInstance(myProject)).getCurrentProfile(); - final InspectionProjectProfileManager inspectionProfileManager = InspectionProjectProfileManager.getInstance(myProject); - Profile profile = inspectionProfileManager.getProfile(currentProfile, false); - if (profile == null) { - profile = InspectionProfileManager.getInstance().getProfile(currentProfile); - if (profile != null) return (InspectionProfile)profile; + public InspectionProfileImpl getCurrentProfile() { + if (myExternalProfile != null) { + return myExternalProfile; + } - final String[] availableProfileNames = inspectionProfileManager.getAvailableProfileNames(); + String currentProfile = ((InspectionManagerBase)InspectionManager.getInstance(myProject)).getCurrentProfile(); + ProjectInspectionProfileManager profileManager = ProjectInspectionProfileManager.getInstanceImpl(myProject); + InspectionProfileImpl profile = profileManager.getProfile(currentProfile, false); + if (profile == null) { + profile = (InspectionProfileImpl)InspectionProfileManager.getInstance().getProfile(currentProfile); + if (profile != null) { + return profile; + } + + final String[] availableProfileNames = profileManager.getAvailableProfileNames(); if (availableProfileNames.length == 0) { //can't be return null; } - profile = inspectionProfileManager.getProfile(availableProfileNames[0]); + profile = profileManager.getProfile(availableProfileNames[0], true); } - return (InspectionProfile)profile; + return profile; } @Override @@ -197,12 +202,8 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G @NotNull public RefManager getRefManager() { if (myRefManager == null) { - myRefManager = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public RefManagerImpl compute() { - return new RefManagerImpl(myProject, myCurrentScope, GlobalInspectionContextBase.this); - } - }); + myRefManager = ApplicationManager.getApplication().runReadAction( + (Computable)() -> new RefManagerImpl(myProject, myCurrentScope, this)); } return myRefManager; } @@ -326,7 +327,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G @NotNull protected List getUsedTools() { - InspectionProfileImpl profile = (InspectionProfileImpl)getCurrentProfile(); + InspectionProfileImpl profile = getCurrentProfile(); List tools = profile.getAllEnabledInspectionTools(myProject); Set dependentTools = new LinkedHashSet<>(); for (Tools tool : tools) { @@ -462,7 +463,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G return totalTotal == 0 ? 1 : 1.0f * totalDone / totalTotal; } - public void setExternalProfile(InspectionProfile profile) { + public void setExternalProfile(InspectionProfileImpl profile) { myExternalProfile = profile; } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextUtil.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextUtil.java index 4ab2c77092cc..5d508ee9a126 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextUtil.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextUtil.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. @@ -16,17 +16,13 @@ package com.intellij.codeInspection.ex; import com.intellij.codeInspection.GlobalInspectionContext; -import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.codeInspection.lang.InspectionExtensionsFactory; import com.intellij.codeInspection.reference.RefElement; -import com.intellij.codeInspection.reference.RefElementImpl; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; -import com.intellij.profile.ProfileManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.search.scope.packageSet.NamedScope; import org.jetbrains.annotations.NotNull; public class GlobalInspectionContextUtil { @@ -40,28 +36,6 @@ public class GlobalInspectionContextUtil { return refElement; } - - public static boolean isToCheckMember(@NotNull RefElement owner, @NotNull InspectionProfileEntry tool, Tools tools, ProfileManager profileManager) { - return isToCheckFile(((RefElementImpl)owner).getContainingFile(), tool, tools, profileManager) && !((RefElementImpl)owner).isSuppressed(tool.getShortName(), tool.getAlternativeID()); - } - - public static boolean isToCheckFile(PsiFile file, @NotNull InspectionProfileEntry tool, Tools tools, ProfileManager profileManager) { - if (tools != null && file != null) { - for (ScopeToolState state : tools.getTools()) { - final NamedScope namedScope = state.getScope(file.getProject()); - if (namedScope == null || namedScope.getValue().contains(file, profileManager.getScopesManager())) { - if (state.isEnabled()) { - InspectionToolWrapper toolWrapper = state.getTool(); - if (toolWrapper.getTool() == tool) return true; - } - return false; - } - } - } - return false; - } - - public static boolean canRunInspections(@NotNull Project project, final boolean online) { for (InspectionExtensionsFactory factory : Extensions.getExtensions(InspectionExtensionsFactory.EP_NAME)) { if (!factory.isProjectConfiguredToRunInspections(project, online)) { diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java index 0556319665dd..610d2790f5f3 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java @@ -31,9 +31,10 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.profile.ProfileEx; -import com.intellij.profile.ProfileManager; +import com.intellij.profile.codeInspection.BaseInspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProfileManager; -import com.intellij.profile.codeInspection.SeverityProvider; +import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; +import com.intellij.project.ProjectKt; import com.intellij.psi.PsiElement; import com.intellij.psi.search.scope.packageSet.NamedScope; import com.intellij.util.ArrayUtil; @@ -87,6 +88,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, private final Object myLock = new Object(); private SchemeDataHolder myDataHolder; + private BaseInspectionProfileManager myProfileManager; InspectionProfileImpl(@NotNull InspectionProfileImpl inspectionProfile) { this(inspectionProfile.getName(), inspectionProfile.myRegistrar, inspectionProfile.getProfileManager(), inspectionProfile.myBaseProfile, null); @@ -100,17 +102,27 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, public InspectionProfileImpl(@NotNull String profileName, @NotNull InspectionToolRegistrar registrar, - @NotNull ProfileManager profileManager) { + @NotNull BaseInspectionProfileManager profileManager) { this(profileName, registrar, profileManager, getBaseProfile(), null); } public InspectionProfileImpl(@NotNull @NonNls String profileName) { - this(profileName, InspectionToolRegistrar.getInstance(), InspectionProfileManager.getInstance(), null, null); + this(profileName, InspectionToolRegistrar.getInstance()); + } + + public InspectionProfileImpl(@NotNull String profileName, @NotNull InspectionToolRegistrar registrar) { + this(profileName, registrar, (BaseInspectionProfileManager)InspectionProfileManager.getInstance(), null, null); } public InspectionProfileImpl(@NotNull String profileName, @NotNull InspectionToolRegistrar registrar, - @NotNull ProfileManager profileManager, + @Nullable InspectionProfileImpl baseProfile) { + this(profileName, registrar, (BaseInspectionProfileManager)InspectionProfileManager.getInstance(), baseProfile, null); + } + + public InspectionProfileImpl(@NotNull String profileName, + @NotNull InspectionToolRegistrar registrar, + @NotNull BaseInspectionProfileManager profileManager, @Nullable InspectionProfileImpl baseProfile, @Nullable SchemeDataHolder dataHolder) { super(profileName); @@ -123,7 +135,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, public InspectionProfileImpl(@NotNull String profileName, @NotNull InspectionToolRegistrar registrar, - @NotNull ProfileManager profileManager, + @NotNull BaseInspectionProfileManager profileManager, @Nullable SchemeDataHolder dataHolder) { this(profileName, registrar, profileManager, getBaseProfile(), dataHolder); } @@ -138,7 +150,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, public List createTools() { return toolWrappers; } - }, InspectionProfileManager.getInstance()); + }, (BaseInspectionProfileManager)InspectionProfileManager.getInstance()); for (InspectionToolWrapper toolWrapper : toolWrappers) { profile.enableTool(toolWrapper.getShortName(), project); } @@ -162,6 +174,16 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, return inspectionTool; } + @NotNull + @Transient + public BaseInspectionProfileManager getProfileManager() { + return myProfileManager; + } + + public void setProfileManager(@NotNull BaseInspectionProfileManager profileManager) { + myProfileManager = profileManager; + } + @NotNull public static InspectionProfileImpl getBaseProfile() { return InspectionProfileImplHolder.DEFAULT_PROFILE; @@ -216,7 +238,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, Project project = element == null ? null : element.getProject(); final ToolsImpl tools = getTools(inspectionToolKey.toString(), project); HighlightDisplayLevel level = tools != null ? tools.getLevel(element) : HighlightDisplayLevel.WARNING; - if (!((SeverityProvider)getProfileManager()).getOwnSeverityRegistrar().isSeverityValid(level.getSeverity().getName())) { + if (!getProfileManager().getOwnSeverityRegistrar().isSeverityValid(level.getSeverity().getName())) { level = HighlightDisplayLevel.WARNING; setErrorLevel(inspectionToolKey, level, project); } @@ -230,7 +252,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, final Element highlightElement = element.getChild(USED_LEVELS); if (highlightElement != null) { // from old profiles - ((SeverityProvider)getProfileManager()).getOwnSeverityRegistrar().readExternal(highlightElement); + getProfileManager().getOwnSeverityRegistrar().readExternal(highlightElement); } String version = element.getAttributeValue(VERSION_TAG); @@ -278,7 +300,18 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, @NotNull public Element writeScheme() { - return myDataHolder == null ? super.writeScheme() : myDataHolder.read(); + if (myDataHolder != null) { + return myDataHolder.read(); + } + + Element element = super.writeScheme(); + if (isProjectLevel()) { + element.setAttribute("version", "1.0"); + } + if (isProjectLevel() && ProjectKt.isDirectoryBased(((ProjectInspectionProfileManager)myProfileManager).getProject())) { + return new Element("component").setAttribute("name", "InspectionProjectProfileManager").addContent(element); + } + return element; } @Override @@ -323,6 +356,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, inspectionElement.setAttribute(CLASS_TAG, toolName); try { toolList.writeExternal(inspectionElement); + //PathMacroManager.getInstance(getProfileManager().pro) } catch (WriteExternalException e) { LOG.error(e); @@ -634,13 +668,13 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel, final Element element = myUninitializedSettings.remove(shortName); try { if (element != null) { - toolsList.readExternal(element, this, dependencies); + toolsList.readExternal(element, getProfileManager(), dependencies); } else if (!myUninitializedSettings.containsKey(InspectionElementsMergerBase.getMergedMarkerName(shortName))) { final InspectionElementsMergerBase merger = getMerger(shortName); Element merged = merger == null ? null : merger.merge(myUninitializedSettings); if (merged != null) { - toolsList.readExternal(merged, this, dependencies); + toolsList.readExternal(merged, getProfileManager(), dependencies); } else if (isProfileLocked()) { // https://youtrack.jetbrains.com/issue/IDEA-158936 diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileWrapper.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileWrapper.java index 9a5d61d6693f..c4352c1c6be1 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileWrapper.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileWrapper.java @@ -17,7 +17,6 @@ package com.intellij.codeInspection.ex; import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInsight.daemon.HighlightDisplayKey; -import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; @@ -43,14 +42,14 @@ public class InspectionProfileWrapper { * I.e. given strategy (if any) receives {@link InspectionProfileWrapper} object that is going to be used so far and returns * {@link InspectionProfileWrapper} object that should be used later. */ - public static final Key> CUSTOMIZATION_KEY = Key.create("Inspection Profile Wrapper Customization"); + public static final Key> CUSTOMIZATION_KEY = Key.create("Inspection Profile Wrapper Customization"); // check whether some inspection got registered twice by accident. 've bit once. private static boolean alreadyChecked; - protected final InspectionProfile myProfile; + protected final InspectionProfileImpl myProfile; - public InspectionProfileWrapper(@NotNull InspectionProfile profile) { + public InspectionProfileWrapper(@NotNull InspectionProfileImpl profile) { myProfile = profile; } @@ -87,7 +86,7 @@ public class InspectionProfileWrapper { } @NotNull - public InspectionProfile getInspectionProfile() { + public InspectionProfileImpl getInspectionProfile() { return myProfile; } } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java index fbdc44cb130d..a9f799443dc6 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java @@ -22,18 +22,16 @@ package com.intellij.codeInspection.ex; import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInsight.daemon.impl.SeverityRegistrar; -import com.intellij.codeInspection.InspectionProfile; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.InvalidDataException; import com.intellij.packageDependencies.DependencyValidationManager; import com.intellij.profile.ProfileEx; -import com.intellij.profile.ProfileManager; -import com.intellij.profile.codeInspection.SeverityProvider; +import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.search.scope.packageSet.*; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.util.SmartList; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -158,10 +156,9 @@ public class ToolsImpl implements Tools { } } - void readExternal(@NotNull Element toolElement, @NotNull InspectionProfile profile, Map> dependencies) throws InvalidDataException { + void readExternal(@NotNull Element toolElement, @NotNull InspectionProfileManager profileManager, Map> dependencies) { final String levelName = toolElement.getAttributeValue(LEVEL_ATTRIBUTE); - final ProfileManager profileManager = profile.getProfileManager(); - final SeverityRegistrar registrar = ((SeverityProvider)profileManager).getOwnSeverityRegistrar(); + final SeverityRegistrar registrar = profileManager.getOwnSeverityRegistrar(); HighlightDisplayLevel level = levelName != null ? HighlightDisplayLevel.find(registrar.getSeverity(levelName)) : null; if (level == null) { level = HighlightDisplayLevel.WARNING; @@ -175,48 +172,50 @@ public class ToolsImpl implements Tools { final InspectionToolWrapper toolWrapper = myDefaultState.getTool(); final List scopeElements = toolElement.getChildren(ProfileEx.SCOPE); - final List scopeNames = new ArrayList<>(); - for (Element scopeElement : scopeElements) { - final String scopeName = scopeElement.getAttributeValue(ProfileEx.NAME); - if (scopeName == null) { - continue; - } - final NamedScopesHolder scopesHolder = profileManager.getScopesManager(); - NamedScope namedScope = null; - if (scopesHolder != null) { - namedScope = scopesHolder.getScope(scopeName); - } - final String errorLevel = scopeElement.getAttributeValue(LEVEL_ATTRIBUTE); - final String enabledInScope = scopeElement.getAttributeValue(ENABLED_ATTRIBUTE); - final InspectionToolWrapper copyToolWrapper = toolWrapper.createCopy(); - // check if unknown children exists - if (scopeElement.getAttributes().size() > 3 || !scopeElement.getChildren().isEmpty()) { - copyToolWrapper.getTool().readSettings(scopeElement); - } - HighlightDisplayLevel scopeLevel = errorLevel != null ? - HighlightDisplayLevel.find(registrar.getSeverity(errorLevel)) : null; - if (scopeLevel == null) { - scopeLevel = level; - } - if (namedScope != null) { - addTool(namedScope, copyToolWrapper, enabledInScope != null && Boolean.parseBoolean(enabledInScope), scopeLevel); - } - else { - addTool(scopeName, copyToolWrapper, enabledInScope != null && Boolean.parseBoolean(enabledInScope), scopeLevel); + if (!scopeElements.isEmpty()) { + final List scopeNames = new SmartList<>(); + for (Element scopeElement : scopeElements) { + final String scopeName = scopeElement.getAttributeValue(ProfileEx.NAME); + if (scopeName == null) { + continue; + } + final NamedScopesHolder scopesHolder = profileManager.getScopesManager(); + NamedScope namedScope = null; + if (scopesHolder != null) { + namedScope = scopesHolder.getScope(scopeName); + } + final String errorLevel = scopeElement.getAttributeValue(LEVEL_ATTRIBUTE); + final String enabledInScope = scopeElement.getAttributeValue(ENABLED_ATTRIBUTE); + final InspectionToolWrapper copyToolWrapper = toolWrapper.createCopy(); + // check if unknown children exists + if (scopeElement.getAttributes().size() > 3 || !scopeElement.getChildren().isEmpty()) { + copyToolWrapper.getTool().readSettings(scopeElement); + } + HighlightDisplayLevel scopeLevel = errorLevel != null ? + HighlightDisplayLevel.find(registrar.getSeverity(errorLevel)) : null; + if (scopeLevel == null) { + scopeLevel = level; + } + if (namedScope != null) { + addTool(namedScope, copyToolWrapper, enabledInScope != null && Boolean.parseBoolean(enabledInScope), scopeLevel); + } + else { + addTool(scopeName, copyToolWrapper, enabledInScope != null && Boolean.parseBoolean(enabledInScope), scopeLevel); + } + + scopeNames.add(scopeName); } - scopeNames.add(scopeName); - } - - for (int i = 0; i < scopeNames.size(); i++) { - String scopeName = scopeNames.get(i); - List order = dependencies.get(scopeName); - if (order == null) { - order = new ArrayList<>(); - dependencies.put(scopeName, order); - } - for (int j = i + 1; j < scopeNames.size(); j++) { - order.add(scopeNames.get(j)); + for (int i = 0; i < scopeNames.size(); i++) { + String scopeName = scopeNames.get(i); + List order = dependencies.get(scopeName); + if (order == null) { + order = new ArrayList<>(); + dependencies.put(scopeName, order); + } + for (int j = i + 1; j < scopeNames.size(); j++) { + order.add(scopeNames.get(j)); + } } } diff --git a/platform/analysis-impl/src/com/intellij/profile/ProfileEx.java b/platform/analysis-impl/src/com/intellij/profile/ProfileEx.java index 6060227b2c09..14ddf42b0d70 100644 --- a/platform/analysis-impl/src/com/intellij/profile/ProfileEx.java +++ b/platform/analysis-impl/src/com/intellij/profile/ProfileEx.java @@ -15,8 +15,6 @@ */ package com.intellij.profile; -import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; -import com.intellij.project.ProjectKt; import com.intellij.util.xmlb.SmartSerializer; import com.intellij.util.xmlb.annotations.OptionTag; import com.intellij.util.xmlb.annotations.Transient; @@ -37,8 +35,6 @@ public abstract class ProfileEx implements Profile { @NotNull protected String myName; - protected ProfileManager myProfileManager; - private boolean myIsProjectLevel; public ProfileEx(@NotNull String name) { @@ -74,18 +70,6 @@ public abstract class ProfileEx implements Profile { myName = name; } - @Override - @NotNull - @Transient - public ProfileManager getProfileManager() { - return myProfileManager; - } - - @Override - public void setProfileManager(@NotNull ProfileManager profileManager) { - myProfileManager = profileManager; - } - public void readExternal(Element element) { mySerializer.readExternal(this, element); } @@ -117,14 +101,7 @@ public abstract class ProfileEx implements Profile { @NotNull public Element writeScheme() { Element element = new Element(PROFILE); - if (isProjectLevel()) { - element.setAttribute("version", "1.0"); - } writeExternal(element); - - if (isProjectLevel() && ProjectKt.isDirectoryBased(((ProjectInspectionProfileManager)myProfileManager).getProject())) { - return new Element("component").setAttribute("name", "InspectionProjectProfileManager").addContent(element); - } return element; } } diff --git a/platform/analysis-impl/src/com/intellij/profile/codeInspection/BaseInspectionProfileManager.kt b/platform/analysis-impl/src/com/intellij/profile/codeInspection/BaseInspectionProfileManager.kt index 2ac621df6eee..235b140fc0ff 100644 --- a/platform/analysis-impl/src/com/intellij/profile/codeInspection/BaseInspectionProfileManager.kt +++ b/platform/analysis-impl/src/com/intellij/profile/codeInspection/BaseInspectionProfileManager.kt @@ -71,7 +71,7 @@ abstract class BaseInspectionProfileManager(messageBus: MessageBus) : Inspectio schemeManager.addScheme(profile) } - override final fun deleteProfile(name: String) { + fun deleteProfile(name: String) { schemeManager.removeScheme(name)?.let { schemeRemoved(it) } @@ -85,8 +85,8 @@ abstract class BaseInspectionProfileManager(messageBus: MessageBus) : Inspectio open protected fun schemeRemoved(scheme: InspectionProfile) { } - override fun updateProfile(profile: Profile) { - schemeManager.addScheme(profile as InspectionProfileImpl) + open fun updateProfile(profile: InspectionProfileImpl) { + schemeManager.addScheme(profile) fireProfileChanged(profile) } } diff --git a/platform/analysis-impl/src/com/intellij/profile/codeInspection/InspectionProfileLoadUtil.java b/platform/analysis-impl/src/com/intellij/profile/codeInspection/InspectionProfileLoadUtil.java index f3ab354c3a7f..96c240864f61 100644 --- a/platform/analysis-impl/src/com/intellij/profile/codeInspection/InspectionProfileLoadUtil.java +++ b/platform/analysis-impl/src/com/intellij/profile/codeInspection/InspectionProfileLoadUtil.java @@ -20,8 +20,6 @@ import com.intellij.codeInspection.ex.InspectionToolRegistrar; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.profile.Profile; -import com.intellij.profile.ProfileManager; import org.jdom.Element; import org.jdom.JDOMException; import org.jetbrains.annotations.NotNull; @@ -45,11 +43,12 @@ public class InspectionProfileLoadUtil { } @NotNull - public static Profile load(@NotNull File file, - @NotNull InspectionToolRegistrar registrar, - @NotNull ProfileManager profileManager) throws JDOMException, IOException, InvalidDataException { + public static InspectionProfileImpl load(@NotNull File file, + @NotNull InspectionToolRegistrar registrar, + @NotNull InspectionProfileManager profileManager) throws JDOMException, IOException, InvalidDataException { Element element = JDOMUtil.load(file); - InspectionProfileImpl profile = new InspectionProfileImpl(getProfileName(file, element), registrar, profileManager); + InspectionProfileImpl profile = new InspectionProfileImpl(getProfileName(file, element), registrar, + (BaseInspectionProfileManager)profileManager); final Element profileElement = element.getChild("profile"); if (profileElement != null) { element = profileElement; diff --git a/platform/analysis-impl/src/com/intellij/profile/codeInspection/InspectionProfileManager.java b/platform/analysis-impl/src/com/intellij/profile/codeInspection/InspectionProfileManager.java index 06bfebf410fd..1d63fc495c3a 100644 --- a/platform/analysis-impl/src/com/intellij/profile/codeInspection/InspectionProfileManager.java +++ b/platform/analysis-impl/src/com/intellij/profile/codeInspection/InspectionProfileManager.java @@ -15,16 +15,28 @@ */ package com.intellij.profile.codeInspection; +import com.intellij.codeInspection.InspectionProfile; +import com.intellij.openapi.Disposable; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; import com.intellij.profile.Profile; -import com.intellij.profile.ProfileManager; +import com.intellij.profile.ProfileChangeAdapter; +import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public interface InspectionProfileManager extends ProfileManager, SeverityProvider { +import java.util.Collection; + +public interface InspectionProfileManager extends SeverityProvider { String INSPECTION_DIR = "inspection"; + @NotNull + Collection getProfiles(); + + default NamedScopesHolder getScopesManager() { + return null; + } + @NotNull static InspectionProfileManager getInstance() { return ServiceManager.getService(InspectionProfileManager.class); @@ -46,4 +58,15 @@ public interface InspectionProfileManager extends ProfileManager, SeverityProvid default Profile getRootProfile() { return getCurrentProfile(); } + + @NotNull + InspectionProfile getCurrentProfile(); + + InspectionProfile getProfile(@NotNull String name, boolean returnRootProfileIfNamedIsAbsent); + + default InspectionProfile getProfile(@NotNull String name) { + return getProfile(name, true); + } + + void addProfileChangeListener(@NotNull ProfileChangeAdapter listener, @NotNull Disposable parent); } \ No newline at end of file diff --git a/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt b/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt index f6a759bfbe13..96fbe275d64b 100644 --- a/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt +++ b/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt @@ -32,7 +32,6 @@ import com.intellij.openapi.startup.StartupActivity import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.text.StringUtil import com.intellij.packageDependencies.DependencyValidationManager -import com.intellij.profile.Profile import com.intellij.profile.ProfileEx import com.intellij.project.isDirectoryBased import com.intellij.psi.search.scope.packageSet.NamedScopeManager @@ -164,10 +163,10 @@ class ProjectInspectionProfileManager(val project: Project, fun isCurrentProfileInitialized() = currentProfile.wasInitialized() - @Synchronized override fun updateProfile(profile: Profile) { + @Synchronized override fun updateProfile(profile: InspectionProfileImpl) { super.updateProfile(profile) - (profile as InspectionProfileImpl).initInspectionTools(project) + profile.initInspectionTools(project) } override fun schemeRemoved(scheme: InspectionProfile) { @@ -264,12 +263,12 @@ class ProjectInspectionProfileManager(val project: Project, override fun getScopesManager() = scopeManager - @Synchronized override fun getProfiles(): Collection { + @Synchronized override fun getProfiles(): Collection { currentProfile return schemeManager.allSchemes } - @Synchronized override fun getAvailableProfileNames(): Array = schemeManager.allSchemeNames.toTypedArray() + @Synchronized fun getAvailableProfileNames(): Array = schemeManager.allSchemeNames.toTypedArray() val projectProfile: String? get() = schemeManager.currentSchemeName @@ -329,8 +328,8 @@ class ProjectInspectionProfileManager(val project: Project, } } - @Synchronized override fun getProfile(name: String, returnRootProfileIfNamedIsAbsent: Boolean): Profile? { + @Synchronized override fun getProfile(name: String, returnRootProfileIfNamedIsAbsent: Boolean): InspectionProfileImpl? { val profile = schemeManager.findSchemeByName(name) - return profile ?: applicationProfileManager.getProfile(name, returnRootProfileIfNamedIsAbsent) + return profile ?: applicationProfileManager.getProfile(name, returnRootProfileIfNamedIsAbsent) as InspectionProfileImpl? } } \ No newline at end of file diff --git a/platform/core-api/src/com/intellij/psi/tree/TokenSet.java b/platform/core-api/src/com/intellij/psi/tree/TokenSet.java index 65254a85d531..6f452d3a7471 100644 --- a/platform/core-api/src/com/intellij/psi/tree/TokenSet.java +++ b/platform/core-api/src/com/intellij/psi/tree/TokenSet.java @@ -31,6 +31,9 @@ public class TokenSet { public static final TokenSet EMPTY = new TokenSet(Short.MAX_VALUE, (short)0) { @Override public boolean contains(IElementType t) { return false; } }; + public static final TokenSet ANY = new TokenSet(Short.MAX_VALUE, (short)0) { + @Override public boolean contains(IElementType t) { return true; } + }; private final short myShift; private final short myMax; diff --git a/platform/core-api/src/com/intellij/ui/LayeredIcon.java b/platform/core-api/src/com/intellij/ui/LayeredIcon.java index 9bb49cc7376a..1e73d2cc615e 100644 --- a/platform/core-api/src/com/intellij/ui/LayeredIcon.java +++ b/platform/core-api/src/com/intellij/ui/LayeredIcon.java @@ -25,7 +25,7 @@ import javax.swing.*; import java.awt.*; import java.util.Arrays; -public class LayeredIcon extends JBUI.ValidatingScalableJBIcon { +public class LayeredIcon extends JBUI.AuxScalableJBIcon { private static final Logger LOG = Logger.getInstance("#com.intellij.ui.LayeredIcon"); private final Icon[] myIcons; private Icon[] myScaledIcons; @@ -60,7 +60,7 @@ public class LayeredIcon extends JBUI.ValidatingScalableJBIcon { myHShifts[i] = scaleVal(myHShifts[i], Scale.JBUI); myVShifts[i] = scaleVal(myVShifts[i], Scale.JBUI); } - adjustSize(); + updateSize(); return this; } @@ -107,7 +107,7 @@ public class LayeredIcon extends JBUI.ValidatingScalableJBIcon { myIcons[layer] = icon; myHShifts[layer] = scaleVal(hShift, Scale.JBUI); myVShifts[layer] = scaleVal(vShift, Scale.JBUI); - adjustSize(); + updateSize(); } /** @@ -178,7 +178,7 @@ public class LayeredIcon extends JBUI.ValidatingScalableJBIcon { @Override public void paintIcon(Component c, Graphics g, int x, int y) { - if (validateJBUIScale()) adjustSize(); + if (updateJBUIScale()) updateSize(); for (int i = 0; i < myIcons.length; i++) { Icon icon = getOrScale(i); if (icon == null || myDisabledLayers[i]) continue; @@ -216,21 +216,21 @@ public class LayeredIcon extends JBUI.ValidatingScalableJBIcon { @Override public int getIconWidth() { - if (myWidth <= 1 || validateJBUIScale()) { - adjustSize(); + if (myWidth <= 1 || updateJBUIScale()) { + updateSize(); } return scaleVal(myWidth, Scale.ARBITRARY); } @Override public int getIconHeight() { - if (myHeight <= 1 || validateJBUIScale()) { - adjustSize(); + if (myHeight <= 1 || updateJBUIScale()) { + updateSize(); } return scaleVal(myHeight, Scale.ARBITRARY); } - protected void adjustSize() { + protected void updateSize() { int minX = Integer.MAX_VALUE; int maxX = Integer.MIN_VALUE; int minY = Integer.MAX_VALUE; @@ -274,7 +274,7 @@ public class LayeredIcon extends JBUI.ValidatingScalableJBIcon { if (getScale() != scale) { super.scale(scale); if (myScaledIcons!= null) Arrays.fill(myScaledIcons, null); - adjustSize(); + updateSize(); } return this; } diff --git a/platform/core-api/src/com/intellij/ui/RowIcon.java b/platform/core-api/src/com/intellij/ui/RowIcon.java index 9eef36f7c6e6..0d9ebe1ca83c 100644 --- a/platform/core-api/src/com/intellij/ui/RowIcon.java +++ b/platform/core-api/src/com/intellij/ui/RowIcon.java @@ -27,7 +27,7 @@ import java.awt.*; import java.util.Arrays; import java.util.List; -public class RowIcon extends JBUI.ValidatingScalableJBIcon { +public class RowIcon extends JBUI.AuxScalableJBIcon { private final Alignment myAlignment; private int myWidth; @@ -51,7 +51,7 @@ public class RowIcon extends JBUI.ValidatingScalableJBIcon { public RowIcon(Icon... icons) { this(icons.length); System.arraycopy(icons, 0, myIcons, 0, icons.length); - adjustSize(); + updateSize(); } @@ -81,7 +81,7 @@ public class RowIcon extends JBUI.ValidatingScalableJBIcon { ScalableIcon icon = (ScalableIcon)myIcons[i]; myScaledIcons[i] = icon == null ? null : icon.scale(getScale()); } - adjustSize(); + updateSize(); } @TestOnly @@ -106,7 +106,7 @@ public class RowIcon extends JBUI.ValidatingScalableJBIcon { public void setIcon(Icon icon, int layer) { myIcons[layer] = icon; rescale(); - adjustSize(); + updateSize(); } public Icon getIcon(int index) { @@ -120,7 +120,7 @@ public class RowIcon extends JBUI.ValidatingScalableJBIcon { @Override public void paintIcon(Component c, Graphics g, int x, int y) { - if (validateJBUIScale()) adjustSize(); + if (updateJBUIScale()) updateSize(); int _x = x; int _y = y; for (Icon icon : getIcons()) { @@ -141,17 +141,17 @@ public class RowIcon extends JBUI.ValidatingScalableJBIcon { @Override public int getIconWidth() { - if (validateJBUIScale()) adjustSize(); + if (updateJBUIScale()) updateSize(); return scaleVal(myWidth, Scale.ARBITRARY); } @Override public int getIconHeight() { - if (validateJBUIScale()) adjustSize(); + if (updateJBUIScale()) updateSize(); return scaleVal(myHeight, Scale.ARBITRARY); } - protected void adjustSize() { + private void updateSize() { int width = 0; int height = 0; for (Icon icon : getIcons()) { diff --git a/platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java index 824202fd0807..b86bce0e66cc 100644 --- a/platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java +++ b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java @@ -33,6 +33,7 @@ public class DefaultWordsScanner extends VersionedWordsScanner { private final TokenSet myCommentTokenSet; private final TokenSet myLiteralTokenSet; private final TokenSet mySkipCodeContextTokenSet; + private final TokenSet myProcessAsWordTokenSet; private boolean myMayHaveFileRefsInLiterals; /** @@ -58,12 +59,29 @@ public class DefaultWordsScanner extends VersionedWordsScanner { * @param skipCodeContextTokenSet the set of token types which should not be considered as code context. */ public DefaultWordsScanner(final Lexer lexer, final TokenSet identifierTokenSet, final TokenSet commentTokenSet, - final TokenSet literalTokenSet, @NotNull TokenSet skipCodeContextTokenSet) { + final TokenSet literalTokenSet, final @NotNull TokenSet skipCodeContextTokenSet) { + this(lexer, identifierTokenSet, commentTokenSet, literalTokenSet, skipCodeContextTokenSet, TokenSet.EMPTY); + } + + /** + * Creates a new instance of the words scanner. + * + * @param lexer the lexer used for breaking the text into tokens. + * @param identifierTokenSet the set of token types which represent identifiers. + * @param commentTokenSet the set of token types which represent comments. + * @param literalTokenSet the set of token types which represent literals. + * @param skipCodeContextTokenSet the set of token types which should not be considered as code context. + * @param processAsWordTokenSet the set of token types which represent overload operators. + */ + public DefaultWordsScanner(final Lexer lexer, final TokenSet identifierTokenSet, final TokenSet commentTokenSet, + final TokenSet literalTokenSet, @NotNull TokenSet skipCodeContextTokenSet, + final @NotNull TokenSet processAsWordTokenSet) { myLexer = lexer; myIdentifierTokenSet = identifierTokenSet; myCommentTokenSet = commentTokenSet; myLiteralTokenSet = literalTokenSet; mySkipCodeContextTokenSet = skipCodeContextTokenSet; + myProcessAsWordTokenSet = processAsWordTokenSet; } public void processWords(CharSequence fileText, Processor processor) { @@ -72,7 +90,11 @@ public class DefaultWordsScanner extends VersionedWordsScanner { IElementType type; while ((type = myLexer.getTokenType()) != null) { - if (myIdentifierTokenSet.contains(type)) { + if (myProcessAsWordTokenSet.contains(type)) { + occurrence.init(fileText, myLexer.getTokenStart(),myLexer.getTokenEnd(), WordOccurrence.Kind.CODE); + processor.process(occurrence); + } + else if (myIdentifierTokenSet.contains(type)) { //occurrence.init(fileText, myLexer.getTokenStart(), myLexer.getTokenEnd(), WordOccurrence.Kind.CODE); //if (!processor.process(occurrence)) return; if (!stripWords(processor, fileText, myLexer.getTokenStart(), myLexer.getTokenEnd(), WordOccurrence.Kind.CODE, occurrence, false)) return; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java index 06746cce6527..c067adc24da3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.codeInsight.daemon.impl; import com.intellij.codeHighlighting.HighlightDisplayLevel; @@ -52,7 +51,6 @@ import com.intellij.openapi.util.Trinity; import com.intellij.openapi.util.text.StringUtil; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; -import com.intellij.profile.codeInspection.SeverityProvider; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.util.CommonProcessors; @@ -111,10 +109,10 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass myShortcutText = ""; } InspectionProfileImpl profileToUse = ProjectInspectionProfileManager.getInstanceImpl(myProject).getCurrentProfile(); - Function custom = file.getUserData(InspectionProfileWrapper.CUSTOMIZATION_KEY); + Function custom = file.getUserData(InspectionProfileWrapper.CUSTOMIZATION_KEY); myProfileWrapper = custom == null ? new InspectionProfileWrapper(profileToUse) : custom.apply(profileToUse); assert myProfileWrapper != null; - mySeverityRegistrar = ((SeverityProvider)myProfileWrapper.getInspectionProfile().getProfileManager()).getSeverityRegistrar(); + mySeverityRegistrar = myProfileWrapper.getInspectionProfile().getProfileManager().getSeverityRegistrar(); // initial guess setProgressLimit(300 * 2); @@ -178,7 +176,6 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass for (InspectionResult inspectionResult : resultList) { LocalInspectionToolWrapper toolWrapper = inspectionResult.tool; for (ProblemDescriptor descriptor : inspectionResult.foundProblems) { - PsiElement psiElement = descriptor.getPsiElement(); if (psiElement == null) continue; if (SuppressionUtil.inspectionResultSuppressed(psiElement, toolWrapper.getTool())) continue; @@ -222,7 +219,8 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass setProgressLimit(toolToSpecifiedLanguageIds.size() * 2L); final LocalInspectionToolSession session = new LocalInspectionToolSession(getFile(), myRestrictRange.getStartOffset(), myRestrictRange.getEndOffset()); - List init = visitPriorityElementsAndInit(toolToSpecifiedLanguageIds, iManager, isOnTheFly, progress, inside, session, toolWrappers, elementDialectIds); + List init = visitPriorityElementsAndInit(toolToSpecifiedLanguageIds, iManager, isOnTheFly, progress, inside, session, + elementDialectIds); inspectInjectedPsi(inside, isOnTheFly, progress, iManager, true, toolWrappers); visitRestElementsAndCleanup(progress, outside, session, init, elementDialectIds); inspectInjectedPsi(outside, isOnTheFly, progress, iManager, false, toolWrappers); @@ -240,7 +238,6 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass @NotNull final ProgressIndicator indicator, @NotNull final List elements, @NotNull final LocalInspectionToolSession session, - @NotNull List wrappers, @NotNull final Set elementDialectIds) { final List init = new ArrayList<>(); List>> entries = new ArrayList<>(toolToSpecifiedLanguageIds.entrySet()); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java b/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java index a483c883c1e9..ef75dc963b62 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java @@ -154,8 +154,7 @@ public class InspectionApplication { final InspectionManagerEx im = (InspectionManagerEx)InspectionManager.getInstance(myProject); - final GlobalInspectionContextImpl inspectionContext = im.createNewGlobalContext(true); - inspectionContext.setExternalProfile((InspectionProfile)inspectionProfile); + im.createNewGlobalContext(true).setExternalProfile((InspectionProfileImpl)inspectionProfile); im.setProfile(inspectionProfile.getName()); final AnalysisScope scope; @@ -214,7 +213,7 @@ public class InspectionApplication { gracefulExit(); return; } - inspectionContext.launchInspectionsOffline(scope, resultsDataPath, myRunGlobalToolsOnly, inspectionsResults); + im.createNewGlobalContext(true).launchInspectionsOffline(scope, resultsDataPath, myRunGlobalToolsOnly, inspectionsResults); logMessageLn(1, "\n" + InspectionsBundle.message("inspection.capitalized.done") + "\n"); if (!myErrorCodeRequired) { closeProject(); @@ -263,7 +262,7 @@ public class InspectionApplication { // convert report if (reportConverter != null) { try { - reportConverter.convert(resultsDataPath, myOutPath, inspectionContext.getTools(), inspectionsResults); + reportConverter.convert(resultsDataPath, myOutPath, im.createNewGlobalContext(true).getTools(), inspectionsResults); } catch (InspectionsReportConverter.ConversionException e) { logError("\n" + e.getMessage()); @@ -307,8 +306,8 @@ public class InspectionApplication { } @Nullable - private Profile loadInspectionProfile() throws IOException, JDOMException { - Profile inspectionProfile = null; + private InspectionProfileImpl loadInspectionProfile() throws IOException, JDOMException { + InspectionProfileImpl inspectionProfile = null; //fetch profile by name from project file (project profiles can be disabled) if (myProfileName != null) { @@ -340,15 +339,15 @@ public class InspectionApplication { if (inspectionProfile != null) return inspectionProfile; } - inspectionProfile = InspectionProjectProfileManager.getInstance(myProject).getCurrentProfile(); + inspectionProfile = (InspectionProfileImpl)InspectionProjectProfileManager.getInstance(myProject).getCurrentProfile(); logError("Using default project profile"); } return inspectionProfile; } @Nullable - private Profile loadProfileByPath(final String profilePath) throws IOException, JDOMException { - Profile inspectionProfile = ApplicationInspectionProfileManager.getInstanceImpl().loadProfile(profilePath); + private InspectionProfileImpl loadProfileByPath(final String profilePath) throws IOException, JDOMException { + InspectionProfileImpl inspectionProfile = ApplicationInspectionProfileManager.getInstanceImpl().loadProfile(profilePath); if (inspectionProfile != null) { logMessageLn(1, "Loaded profile \'" + inspectionProfile.getName() + "\' from file \'" + profilePath + "\'"); } @@ -356,17 +355,17 @@ public class InspectionApplication { } @Nullable - private Profile loadProfileByName(final String profileName) { - Profile inspectionProfile = InspectionProjectProfileManager.getInstance(myProject).getProfile(profileName, false); + private InspectionProfileImpl loadProfileByName(final String profileName) { + InspectionProfileImpl inspectionProfile = + (InspectionProfileImpl)InspectionProjectProfileManager.getInstance(myProject).getProfile(profileName, false); if (inspectionProfile != null) { logMessageLn(1, "Loaded shared project profile \'" + profileName + "\'"); } else { //check if ide profile is used for project - final Collection profiles = InspectionProjectProfileManager.getInstance(myProject).getProfiles(); - for (Profile profile : profiles) { + for (InspectionProfile profile : InspectionProjectProfileManager.getInstance(myProject).getProfiles()) { if (Comparing.strEqual(profile.getName(), profileName)) { - inspectionProfile = profile; + inspectionProfile = (InspectionProfileImpl)profile; logMessageLn(1, "Loaded local profile \'" + profileName + "\'"); break; } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeInspectionAction.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeInspectionAction.java index 5eac29f164d2..5ff9a2463391 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeInspectionAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeInspectionAction.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.codeInspection.actions; import com.intellij.analysis.AnalysisScope; @@ -47,7 +46,7 @@ import java.util.List; public class CodeInspectionAction extends BaseAnalysisAction { private GlobalInspectionContextImpl myGlobalInspectionContext; - protected InspectionProfile myExternalProfile; + protected InspectionProfileImpl myExternalProfile; public CodeInspectionAction() { super(InspectionsBundle.message("inspection.action.title"), InspectionsBundle.message("inspection.action.noun")); @@ -124,7 +123,7 @@ public class CodeInspectionAction extends BaseAnalysisAction { profiles.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - myExternalProfile = (InspectionProfile)profiles.getSelectedItem(); + myExternalProfile = (InspectionProfileImpl)profiles.getSelectedItem(); final boolean canExecute = myExternalProfile != null && myExternalProfile.isExecutable(project); dialog.setOKActionEnabled(canExecute); if (canExecute) { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeInspectionOnEditorAction.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeInspectionOnEditorAction.java index 68c8c9191f6f..43bd164f3726 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeInspectionOnEditorAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/CodeInspectionOnEditorAction.java @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.codeInspection.actions; import com.intellij.analysis.AnalysisScope; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInspection.InspectionManager; -import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; import com.intellij.codeInspection.ex.InspectionManagerEx; +import com.intellij.codeInspection.ex.InspectionProfileImpl; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -51,9 +50,7 @@ public class CodeInspectionOnEditorAction extends AnAction { final AnalysisScope scope = new AnalysisScope(psiFile); final GlobalInspectionContextImpl inspectionContext = inspectionManagerEx.createNewGlobalContext(false); inspectionContext.setCurrentScope(scope); - final InspectionProfile inspectionProfile = - InspectionProjectProfileManager.getInstance(project).getCurrentProfile(); - inspectionContext.setExternalProfile(inspectionProfile); + inspectionContext.setExternalProfile((InspectionProfileImpl)InspectionProjectProfileManager.getInstance(project).getCurrentProfile()); inspectionContext.doInspections(scope); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java index a53b517c0022..28efc417b0c2 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java @@ -26,7 +26,6 @@ import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInspection.InspectionApplication; import com.intellij.codeInspection.InspectionManager; -import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; import com.intellij.codeInspection.ex.InspectionManagerEx; @@ -111,13 +110,7 @@ public class ViewOfflineResultsAction extends AnAction { final String extension = inspectionFile.getExtension(); if (shortName.equals(InspectionApplication.DESCRIPTIONS)) { profileName[0] = ApplicationManager.getApplication().runReadAction( - new Computable() { - @Override - @Nullable - public String compute() { - return OfflineViewParseUtil.parseProfileName(LoadTextUtil.loadText(inspectionFile).toString()); - } - } + (Computable)() -> OfflineViewParseUtil.parseProfileName(LoadTextUtil.loadText(inspectionFile).toString()) ); } else if (XML_EXTENSION.equals(extension)) { @@ -184,7 +177,7 @@ public class ViewOfflineResultsAction extends AnAction { @NotNull public static InspectionResultsView showOfflineView(@NotNull Project project, @NotNull Map>> resMap, - @NotNull InspectionProfile inspectionProfile, + @NotNull InspectionProfileImpl inspectionProfile, @NotNull String title) { final AnalysisScope scope = new AnalysisScope(project); final InspectionManagerEx managerEx = (InspectionManagerEx)InspectionManager.getInstance(project); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/ApplicationInspectionProfileManager.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/ApplicationInspectionProfileManager.java index cdb88bebf4aa..6bb512792629 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/ApplicationInspectionProfileManager.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/ApplicationInspectionProfileManager.java @@ -22,6 +22,7 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.daemon.impl.SeveritiesProvider; import com.intellij.codeInsight.daemon.impl.SeverityRegistrar; import com.intellij.codeInsight.daemon.impl.analysis.HighlightingSettingsPerFile; +import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.configurationStore.BundledSchemeEP; import com.intellij.configurationStore.SchemeDataHolder; @@ -40,9 +41,7 @@ import com.intellij.openapi.options.SchemeManagerFactory; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.Messages; -import com.intellij.profile.Profile; import com.intellij.profile.codeInspection.*; -import com.intellij.util.ArrayUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.messages.MessageBus; import com.intellij.util.ui.UIUtil; @@ -149,7 +148,7 @@ public class ApplicationInspectionProfileManager extends BaseInspectionProfileMa @Override @NotNull - public Collection getProfiles() { + public Collection getProfiles() { initProfiles(); return Collections.unmodifiableList(mySchemeManager.getAllSchemes()); } @@ -186,7 +185,7 @@ public class ApplicationInspectionProfileManager extends BaseInspectionProfileMa return ApplicationManager.getApplication().isUnitTestMode() || ApplicationManager.getApplication().isHeadlessEnvironment(); } - public Profile loadProfile(@NotNull String path) throws IOException, JDOMException { + public InspectionProfileImpl loadProfile(@NotNull String path) throws IOException, JDOMException { final File file = new File(path); if (file.exists()) { try { @@ -205,9 +204,9 @@ public class ApplicationInspectionProfileManager extends BaseInspectionProfileMa } @Override - public void updateProfile(@NotNull Profile profile) { + public void updateProfile(@NotNull InspectionProfileImpl profile) { super.updateProfile(profile); - updateProfileImpl((InspectionProfileImpl)profile); + updateProfileImpl(profile); } private static void updateProfileImpl(@NotNull InspectionProfileImpl profile) { @@ -239,9 +238,11 @@ public class ApplicationInspectionProfileManager extends BaseInspectionProfileMa } @Override - public Profile getProfile(@NotNull final String name, boolean returnRootProfileIfNamedIsAbsent) { - Profile found = mySchemeManager.findSchemeByName(name); - if (found != null) return found; + public InspectionProfileImpl getProfile(@NotNull final String name, boolean returnRootProfileIfNamedIsAbsent) { + InspectionProfileImpl found = mySchemeManager.findSchemeByName(name); + if (found != null) { + return found; + } //profile was deleted if (returnRootProfileIfNamedIsAbsent) { return getCurrentProfile(); @@ -272,12 +273,6 @@ public class ApplicationInspectionProfileManager extends BaseInspectionProfileMa return ObjectUtils.chooseNotNull(mySchemeManager.getCurrentSchemeName(), InspectionProfileImpl.DEFAULT_PROFILE_NAME); } - @Override - @NotNull - public String[] getAvailableProfileNames() { - return ArrayUtil.toStringArray(mySchemeManager.getAllSchemeNames()); - } - public static void onProfilesChanged() { //cleanup caches blindly for all projects in case ide profile was modified for (final Project project : ProjectManager.getInstance().getOpenProjects()) { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index 27a8afebe95a..97051be0610c 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -108,7 +108,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private final ConcurrentMap> myGroups = ContainerUtil.newConcurrentMap(); private final OccurenceNavigator myOccurenceNavigator; - private volatile InspectionProfile myInspectionProfile; + private volatile InspectionProfileImpl myInspectionProfile; @NotNull private final AnalysisScope myScope; @NonNls @@ -617,9 +617,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren if (reuseEditorFor(document)) { myPreviewEditor.putUserData(PREVIEW_EDITOR_IS_REUSED_KEY, true); - myPreviewEditor.getFoldingModel().runBatchFoldingOperation(() -> { - myPreviewEditor.getFoldingModel().clearFoldRegions(); - }); + myPreviewEditor.getFoldingModel().runBatchFoldingOperation(() -> myPreviewEditor.getFoldingModel().clearFoldRegions()); myPreviewEditor.getMarkupModel().removeAllHighlighters(); } else { @@ -805,7 +803,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private void addToolsSynchronously(Collection tools) { if (isDisposed()) return; synchronized (myTreeStructureUpdateLock) { - InspectionProfileImpl profile = (InspectionProfileImpl)myInspectionProfile; + InspectionProfileImpl profile = myInspectionProfile; boolean isGroupedBySeverity = myGlobalInspectionContext.getUIOptions().GROUP_BY_SEVERITY; boolean singleInspectionRun = isSingleInspectionRun(); for (Tools currentTools : tools) { @@ -1132,7 +1130,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren public void updateCurrentProfile() { final String name = myInspectionProfile.getName(); - myInspectionProfile = (InspectionProfile)myInspectionProfile.getProfileManager().getProfile(name); + myInspectionProfile = (InspectionProfileImpl)myInspectionProfile.getProfileManager().getProfile(name); } private class RerunAction extends AnAction { diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java index 3d80ea0d5828..a1bf4487aee4 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java @@ -17,7 +17,7 @@ package com.intellij.find.impl; import com.google.common.collect.HashMultiset; import com.google.common.collect.Multiset; -import com.intellij.concurrency.JobLauncher; +import com.intellij.concurrency.JobSchedulerImpl; import com.intellij.find.FindBundle; import com.intellij.find.FindModel; import com.intellij.find.findInProject.FindInProjectManager; @@ -30,10 +30,8 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.progress.EmptyProgressIndicator; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.*; +import com.intellij.openapi.progress.util.ProgressWrapper; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectUtil; @@ -59,8 +57,8 @@ import com.intellij.usageView.UsageInfo; import com.intellij.usages.FindUsagesProcessPresentation; import com.intellij.usages.UsageLimitUtil; import com.intellij.usages.impl.UsageViewManagerImpl; -import com.intellij.util.Processor; -import com.intellij.util.Processors; +import com.intellij.util.*; +import com.intellij.util.concurrency.AppExecutorUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.FileBasedIndex; import com.intellij.util.indexing.FileBasedIndexImpl; @@ -68,6 +66,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -76,6 +77,7 @@ import java.util.concurrent.atomic.AtomicLong; * @author peter */ class FindInProjectTask { + private static final ExecutorService ourExecutor = AppExecutorUtil.createBoundedApplicationPoolExecutor("find in path", JobSchedulerImpl.CORES_COUNT); private static final Logger LOG = Logger.getInstance("#com.intellij.find.impl.FindInProjectTask"); private static final int FILES_SIZE_LIMIT = 70 * 1024 * 1024; // megabytes. private static final int SINGLE_FILE_SIZE_LIMIT = 5 * 1024 * 1024; // megabytes. @@ -195,19 +197,19 @@ class FindInProjectTask { AtomicInteger i = new AtomicInteger(); AtomicInteger count = new AtomicInteger(); - Processor processor = virtualFile -> { + Consumer searchInFile = virtualFile -> { final int index = i.incrementAndGet(); - if (!virtualFile.isValid()) return true; + if (!virtualFile.isValid()) return; long fileLength = UsageViewManagerImpl.getFileLength(virtualFile); - if (fileLength == -1) return true; // Binary or invalid + if (fileLength == -1) return; // Binary or invalid final boolean skipProjectFile = ProjectUtil.isProjectOrWorkspaceFile(virtualFile) && !myFindModel.isSearchInProjectFiles(); - if (skipProjectFile && !Registry.is("find.search.in.project.files")) return true; + if (skipProjectFile && !Registry.is("find.search.in.project.files")) return; if (fileLength > SINGLE_FILE_SIZE_LIMIT) { myLargeFiles.add(virtualFile); - return true; + return; } myProgress.checkCanceled(); @@ -218,7 +220,7 @@ class FindInProjectTask { myProgress.setText2(FindBundle.message("find.searching.for.string.in.file.occurrences.progress", count)); PsiFile psiFile = ReadAction.compute(() -> findFile(virtualFile)); - if (psiFile == null) return true; + if (psiFile == null) return; int countInFile = FindInProjectUtil.processUsagesInFile(psiFile, myFindModel, info -> skipProjectFile || consumer.process(info)); @@ -228,7 +230,7 @@ class FindInProjectTask { model.setSearchInProjectFiles(true); FindInProjectManager.getInstance(myProject).startFindInProject(model); }); - return true; + return; } count.addAndGet(countInFile); @@ -240,9 +242,31 @@ class FindInProjectTask { UsageLimitUtil.showAndCancelIfAborted(myProject, message, processPresentation.getUsageViewPresentation()); } } - return true; }; - JobLauncher.getInstance().invokeConcurrentlyUnderProgress(new ArrayList<>(virtualFiles), myProgress, false, processor); + forkJoin(virtualFiles, searchInFile); + } + + private static void forkJoin(@NotNull Collection virtualFiles, Consumer searchInFile) { + ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator(); + List> futures = ContainerUtil.map(virtualFiles, file -> ourExecutor.submit(() -> { + ProgressIndicator wrapper = indicator == null ? new EmptyProgressIndicator() : ProgressWrapper.wrap(indicator); + ProgressManager.getInstance().runProcess(() -> searchInFile.consume(file), wrapper); + })); + waitForFutures(futures); + } + + private static void waitForFutures(List> futures) { + for (Future future : futures) { + try { + future.get(); + } + catch (InterruptedException e) { + throw new ProcessCanceledException(); + } + catch (ExecutionException e) { + ExceptionUtil.rethrowAllAsUnchecked(e.getCause()); + } + } } // must return non-binary files diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java index f12aeabb2ad2..26bbe600688b 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java @@ -253,7 +253,10 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane @NotNull public ActionCallback selectCB(Object element, VirtualFile file, boolean requestFocus) { if (file != null) { - return ((BaseProjectTreeBuilder)getTreeBuilder()).select(element, file, requestFocus); + BaseProjectTreeBuilder builder = (BaseProjectTreeBuilder)getTreeBuilder(); + // actually, getInitialized().doWhenDone() should be called by builder internally + // this will be done in 2017 + return builder.getInitialized().doWhenDone(() -> builder.select(element, file, requestFocus)); } return ActionCallback.DONE; } diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileActions.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileActions.java index 84f28cc7f313..151a1b19f18b 100644 --- a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileActions.java +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileActions.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 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,6 +16,7 @@ package com.intellij.ide.scratch; import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.icons.AllIcons; import com.intellij.lang.Language; import com.intellij.lang.LanguageUtil; import com.intellij.lang.PerFileMappings; @@ -23,6 +24,7 @@ import com.intellij.lang.StdLanguages; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManager; @@ -35,6 +37,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.ui.LayeredIcon; import com.intellij.util.Consumer; import com.intellij.util.Function; import com.intellij.util.ObjectUtils; @@ -44,6 +47,7 @@ import com.intellij.util.containers.JBIterable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.util.Set; import static com.intellij.openapi.util.Conditions.not; @@ -55,11 +59,14 @@ import static com.intellij.openapi.util.Conditions.notNull; public class ScratchFileActions { public static class NewFileAction extends DumbAwareAction { + private static final Icon ICON = LayeredIcon.create(AllIcons.FileTypes.Text, AllIcons.Actions.Scratch); @Override public void update(@NotNull AnActionEvent e) { boolean enabled = e.getProject() != null && Registry.is("ide.scratch.enabled"); - e.getPresentation().setEnabledAndVisible(enabled); + Presentation presentation = e.getPresentation(); + presentation.setEnabledAndVisible(enabled); + presentation.setIcon(ICON); } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/structureView/customRegions/CustomRegionStructureUtil.java b/platform/lang-impl/src/com/intellij/ide/structureView/customRegions/CustomRegionStructureUtil.java index d66fcc32447f..9386040f21f1 100644 --- a/platform/lang-impl/src/com/intellij/ide/structureView/customRegions/CustomRegionStructureUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/structureView/customRegions/CustomRegionStructureUtil.java @@ -64,17 +64,15 @@ public class CustomRegionStructureUtil { } private static Collection collectCustomRegions(@NotNull PsiElement rootElement, @NotNull Set ranges) { - Iterator iterator = SyntaxTraverser.psiTraverser(rootElement) - .regard(element -> !isInsideRanges(element, ranges)) - .filter(PsiComment.class) - .filter(comment -> !comment.textContains('\n')) + Iterator iterator = SyntaxTraverser.psiTraverser(rootElement) + .regard(element -> isCustomRegionCommentCandidate(element) && !isInsideRanges(element, ranges)) .iterator(); List customRegions = ContainerUtil.newSmartList(); CustomRegionTreeElement currRegionElement = null; CustomFoldingProvider provider = null; while (iterator.hasNext()) { - PsiComment child = iterator.next(); + PsiElement child = iterator.next(); if (provider == null) provider = getProvider(child); if (provider != null) { String commentText = child.getText(); @@ -107,10 +105,15 @@ public class CustomRegionStructureUtil { private static boolean isInsideRanges(@NotNull PsiElement element, @NotNull Set ranges) { for (TextRange range : ranges) { - if (range.contains(element.getTextRange().getStartOffset()) || range.contains(element.getTextRange().getEndOffset())) { + TextRange elementRange = element.getTextRange(); + if (range.contains(elementRange.getStartOffset()) || range.contains(elementRange.getEndOffset())) { return true; } } return false; } + + private static boolean isCustomRegionCommentCandidate(@NotNull PsiElement element) { + return element instanceof PsiComment && !element.textContains('\n'); + } } 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 b28890076aa8..5d9d795c5f79 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 @@ -21,7 +21,6 @@ import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.daemon.impl.SeverityRegistrar; import com.intellij.codeInsight.hint.HintUtil; -import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ModifiableModel; import com.intellij.codeInspection.ex.*; @@ -45,10 +44,9 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.profile.ProfileManager; +import com.intellij.profile.codeInspection.BaseInspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; -import com.intellij.profile.codeInspection.SeverityProvider; import com.intellij.profile.codeInspection.ui.filter.InspectionFilterAction; import com.intellij.profile.codeInspection.ui.filter.InspectionsFilter; import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionConfigTreeNode; @@ -88,6 +86,8 @@ import java.io.StringReader; import java.util.*; import java.util.List; +import com.intellij.util.containers.Queue; + public class SingleInspectionProfilePanel extends JPanel { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.InspectionToolsPanel"); @NonNls private static final String INSPECTION_FILTER_HISTORY = "INSPECTION_FILTER_HISTORY"; @@ -268,9 +268,9 @@ public class SingleInspectionProfilePanel extends JPanel { return child; } - private static void copyUsedSeveritiesIfUndefined(final ModifiableModel selectedProfile, final ProfileManager profileManager) { - final SeverityRegistrar registrar = ((SeverityProvider)profileManager).getSeverityRegistrar(); - final Set severities = ((InspectionProfileImpl)selectedProfile).getUsedSeverities(); + private static void copyUsedSeveritiesIfUndefined(InspectionProfileImpl selectedProfile, BaseInspectionProfileManager profileManager) { + final SeverityRegistrar registrar = profileManager.getSeverityRegistrar(); + final Set severities = selectedProfile.getUsedSeverities(); for (Iterator iterator = severities.iterator(); iterator.hasNext();) { HighlightSeverity severity = iterator.next(); if (registrar.isSeverityValid(severity.getName())) { @@ -279,7 +279,7 @@ public class SingleInspectionProfilePanel extends JPanel { } if (!severities.isEmpty()) { - final SeverityRegistrar oppositeRegister = ((SeverityProvider)selectedProfile.getProfileManager()).getSeverityRegistrar(); + final SeverityRegistrar oppositeRegister = selectedProfile.getProfileManager().getSeverityRegistrar(); for (HighlightSeverity severity : severities) { final TextAttributesKey attributesKey = TextAttributesKey.find(severity.getName()); final TextAttributes textAttributes = oppositeRegister.getTextAttributesBySeverity(severity); @@ -694,7 +694,7 @@ public class SingleInspectionProfilePanel extends JPanel { private JPopupMenu compoundPopup() { final DefaultActionGroup group = new DefaultActionGroup(); - final SeverityRegistrar severityRegistrar = ((SeverityProvider)myProfile.getProfileManager()).getOwnSeverityRegistrar(); + final SeverityRegistrar severityRegistrar = myProfile.getProfileManager().getOwnSeverityRegistrar(); for (HighlightSeverity severity : LevelChooserAction.getSeverities(severityRegistrar, includeDoNotShow())) { final HighlightDisplayLevel level = HighlightDisplayLevel.find(severity); group.add(new AnAction(renderSeverity(severity), renderSeverity(severity), level.getIcon()) { @@ -834,7 +834,7 @@ public class SingleInspectionProfilePanel extends JPanel { if (scopesNames.isEmpty()) { final LevelChooserAction severityLevelChooser = - new LevelChooserAction(((SeverityProvider)myProfile.getProfileManager()).getOwnSeverityRegistrar(), + new LevelChooserAction(myProfile.getProfileManager().getOwnSeverityRegistrar(), includeDoNotShow(nodes)) { @Override protected void onChosen(final HighlightSeverity severity) { @@ -1014,7 +1014,7 @@ public class SingleInspectionProfilePanel extends JPanel { return modified; } - public ModifiableModel getProfile() { + public InspectionProfileImpl getProfile() { return myProfile; } @@ -1117,10 +1117,10 @@ public class SingleInspectionProfilePanel extends JPanel { if (!modified) { return; } - final ModifiableModel selectedProfile = getProfile(); + final InspectionProfileImpl selectedProfile = getProfile(); - ProfileManager profileManager = selectedProfile.isProjectLevel() ? myProjectProfileManager : InspectionProfileManager.getInstance(); - InspectionProfile parentProfile = selectedProfile.getParentProfile(); + BaseInspectionProfileManager profileManager = selectedProfile.isProjectLevel() ? myProjectProfileManager : (BaseInspectionProfileManager)InspectionProfileManager.getInstance(); + InspectionProfileImpl parentProfile = (InspectionProfileImpl)selectedProfile.getParentProfile(); if (parentProfile.getProfileManager().getProfile(parentProfile.getName(), false) == parentProfile) { parentProfile.getProfileManager().deleteProfile(parentProfile.getName()); @@ -1128,12 +1128,13 @@ public class SingleInspectionProfilePanel extends JPanel { if (selectedProfile.getProfileManager() != profileManager) { copyUsedSeveritiesIfUndefined(selectedProfile, profileManager); selectedProfile.setProfileManager(profileManager); - } else { + } + else { selectedProfile.getProfileManager().updateProfile(selectedProfile); } selectedProfile.commit(); - myProfile = (InspectionProfileImpl)parentProfile.getModifiableModel(); + myProfile = parentProfile.getModifiableModel(); setSelectedProfileModified(false); myModified = false; myRoot.dropCache(); diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java index 9da66f7a13d8..35f64489ceb3 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java @@ -47,7 +47,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.profile.Profile; -import com.intellij.profile.ProfileManager; +import com.intellij.profile.codeInspection.BaseInspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; import com.intellij.profile.codeInspection.ui.ErrorsConfigurable; @@ -82,10 +82,10 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable private static final Logger LOG = Logger.getInstance(InspectionToolsConfigurable.class); private static final Pattern COPIED_PROFILE_SUFFIX_PATTERN = Pattern.compile("(.*\\s*copy)\\s*(\\d*)"); - protected final InspectionProfileManager myApplicationProfileManager; + protected final BaseInspectionProfileManager myApplicationProfileManager; protected final ProjectInspectionProfileManager myProjectProfileManager; private final List myPanels = new ArrayList<>(); - private final List myDeletedProfiles = new ArrayList<>(); + private final List myDeletedProfiles = new ArrayList<>(); protected ProfilesChooser myProfiles; private JPanel myProfilePanelHolder; private AuxiliaryRightPanel myAuxiliaryRightPanel; @@ -93,7 +93,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable public InspectionToolsConfigurable(@NotNull ProjectInspectionProfileManager projectProfileManager) { myProjectProfileManager = projectProfileManager; - myApplicationProfileManager = InspectionProfileManager.getInstance(); + myApplicationProfileManager = (BaseInspectionProfileManager)InspectionProfileManager.getInstance(); } private static JComponent withBorderOnTop(final JComponent component) { @@ -138,7 +138,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable } } - ProfileManager profileManager = isProjectLevel ? myProjectProfileManager : myApplicationProfileManager; + BaseInspectionProfileManager profileManager = isProjectLevel ? myProjectProfileManager : myApplicationProfileManager; InspectionProfileImpl inspectionProfile = new InspectionProfileImpl(profileDefaultName, InspectionToolRegistrar.getInstance(), profileManager); @@ -377,7 +377,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable Messages.getInformationIcon()) != Messages.OK) { return; } - myProfiles.getProfilesComboBox().removeProfile((InspectionProfileImpl)existed.getProfile()); + myProfiles.getProfilesComboBox().removeProfile(existed.getProfile()); myPanels.remove(existed); } final ModifiableModel model = profile.getModifiableModel(); @@ -422,7 +422,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable } public static InspectionProfileImpl importInspectionProfile(@NotNull Element rootElement, - @NotNull InspectionProfileManager profileManager, + @NotNull BaseInspectionProfileManager profileManager, @NotNull Project project, @Nullable JPanel anchorPanel) throws JDOMException, IOException, InvalidDataException { @@ -503,7 +503,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable @Override public void apply() throws ConfigurationException { SingleInspectionProfilePanel selectedPanel = getSelectedPanel(); - for (Profile profile : myDeletedProfiles) { + for (InspectionProfileImpl profile : myDeletedProfiles) { deleteProfile(profile); } myDeletedProfiles.clear(); @@ -518,7 +518,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable protected abstract void applyRootProfile(@NotNull String name, boolean isProjectLevel); - private void deleteProfile(@NotNull Profile profile) { + private void deleteProfile(@NotNull InspectionProfileImpl profile) { if (profile.getProfileManager() == myApplicationProfileManager) { myApplicationProfileManager.deleteProfile(profile.getName()); } @@ -572,8 +572,6 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable } private boolean isDeleteEnabled(@NotNull InspectionProfileImpl inspectionProfile) { - final ProfileManager profileManager = inspectionProfile.getProfileManager(); - boolean projectProfileFound = false; boolean ideProfileFound = false; @@ -586,7 +584,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable if (ideProfileFound && projectProfileFound) break; } - return profileManager == myProjectProfileManager ? projectProfileFound : ideProfileFound; + return inspectionProfile.getProfileManager() == myProjectProfileManager ? projectProfileFound : ideProfileFound; } protected Collection getProfiles() { diff --git a/platform/platform-api/src/com/intellij/ui/ScrollingUtil.java b/platform/platform-api/src/com/intellij/ui/ScrollingUtil.java index f511326b3365..b421414fc031 100644 --- a/platform/platform-api/src/com/intellij/ui/ScrollingUtil.java +++ b/platform/platform-api/src/com/intellij/ui/ScrollingUtil.java @@ -431,7 +431,13 @@ public class ScrollingUtil { } else { return Math.min(row + 1, table.getRowCount() - 1); // just in case } + } + public static boolean isVisible(JTable table, int row) { + Rectangle visibleRect = table.getVisibleRect(); + int start = getLeadingRow(table, visibleRect); + int end = getTrailingRow(table, visibleRect); + return row >= start && row <= end; } private static int getTrailingRow(JTable table, Rectangle visibleRect) { diff --git a/platform/platform-impl/src/com/intellij/ide/CharToVKeyMap.java b/platform/platform-impl/src/com/intellij/ide/CharToVKeyMap.java index f7ca31506c6c..9f6ff75a61c1 100644 --- a/platform/platform-impl/src/com/intellij/ide/CharToVKeyMap.java +++ b/platform/platform-impl/src/com/intellij/ide/CharToVKeyMap.java @@ -15,20 +15,19 @@ */ package com.intellij.ide; +import gnu.trove.TObjectIntHashMap; + import java.awt.event.KeyEvent; -import java.util.HashMap; /** * @author Denis Fokin */ class CharToVKeyMap { - private CharToVKeyMap() {} - private static HashMap charToVKeyMap = - new HashMap<>(); + private static final TObjectIntHashMap charToVKeyMap = new TObjectIntHashMap<>(); - public static Integer get (Character ch) { + public static int get(Character ch) { return charToVKeyMap.containsKey(ch) ? charToVKeyMap.get(ch) : KeyEvent.VK_UNDEFINED; } diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index f563e2e736c5..ac5aaf7098b5 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -59,10 +59,8 @@ import java.awt.event.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.LinkedHashSet; +import java.util.*; import java.util.List; -import java.util.Map; -import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; /** @@ -117,8 +115,8 @@ public class IdeEventQueue extends EventQueue { private AWTEvent myCurrentEvent; private long myLastActiveTime; private WindowManagerEx myWindowManager; - private final Set myDispatchers = new LinkedHashSet<>(); - private final Set myPostProcessors = new LinkedHashSet<>(); + private final List myDispatchers = ContainerUtil.createLockFreeCopyOnWriteList(); + private final List myPostProcessors = ContainerUtil.createLockFreeCopyOnWriteList(); private final Set myReady = ContainerUtil.newHashSet(); private boolean myKeyboardBusy; private boolean myDispatchingFocusEvent; @@ -280,28 +278,27 @@ public class IdeEventQueue extends EventQueue { } } - - public void addDispatcher(final EventDispatcher dispatcher, Disposable parent) { + public void addDispatcher(@NotNull EventDispatcher dispatcher, Disposable parent) { _addProcessor(dispatcher, parent, myDispatchers); } - public void removeDispatcher(EventDispatcher dispatcher) { + public void removeDispatcher(@NotNull EventDispatcher dispatcher) { myDispatchers.remove(dispatcher); } - public boolean containsDispatcher(EventDispatcher dispatcher) { + public boolean containsDispatcher(@NotNull EventDispatcher dispatcher) { return myDispatchers.contains(dispatcher); } - public void addPostprocessor(EventDispatcher dispatcher, @Nullable Disposable parent) { + public void addPostprocessor(@NotNull EventDispatcher dispatcher, @Nullable Disposable parent) { _addProcessor(dispatcher, parent, myPostProcessors); } - public void removePostprocessor(EventDispatcher dispatcher) { + public void removePostprocessor(@NotNull EventDispatcher dispatcher) { myPostProcessors.remove(dispatcher); } - private static void _addProcessor(final EventDispatcher dispatcher, Disposable parent, final Set set) { + private static void _addProcessor(@NotNull EventDispatcher dispatcher, Disposable parent, @NotNull Collection set) { set.add(dispatcher); if (parent != null) { Disposer.register(parent, () -> set.remove(dispatcher)); @@ -325,7 +322,8 @@ public class IdeEventQueue extends EventQueue { private static Component wheelDestinationComponent; private static long lastMouseWheel; - private static AWTEvent changeSourceIfNeeded(AWTEvent awtEvent) { + @NotNull + private static AWTEvent changeSourceIfNeeded(@NotNull AWTEvent awtEvent) { if (SystemInfo.isMac && Registry.is("ide.inertial.mouse.fix") && awtEvent instanceof MouseWheelEvent) { MouseWheelEvent mwe = (MouseWheelEvent) awtEvent; if (mwe.getWhen() - lastMouseWheel > MOUSE_WHEEL_RESTART_THRESHOLD) { @@ -412,6 +410,7 @@ public class IdeEventQueue extends EventQueue { } @Override + @NotNull public AWTEvent getNextEvent() throws InterruptedException { AWTEvent event = super.getNextEvent(); if (isKeyboardEvent(event) && myKeyboardEventsDispatched.incrementAndGet() > myKeyboardEventsPosted.get()) { @@ -421,7 +420,7 @@ public class IdeEventQueue extends EventQueue { } @Nullable - static AccessToken startActivity(AWTEvent e) { + static AccessToken startActivity(@NotNull AWTEvent e) { if (ourTransactionGuard == null && appIsLoaded()) { if (ApplicationManager.getApplication() != null && !ApplicationManager.getApplication().isDisposed()) { ourTransactionGuard = (TransactionGuardImpl)TransactionGuard.getInstance(); @@ -432,17 +431,14 @@ public class IdeEventQueue extends EventQueue { : ourTransactionGuard.startActivity(isInputEvent(e) || e instanceof ItemEvent || e instanceof FocusEvent); } - private void processException(Throwable t) { + private void processException(@NotNull Throwable t) { if (!myToolkitBugsProcessor.process(t)) { PluginManager.processException(t); } } - private static int ctrlIsPressedCount; - private static boolean leftAltIsPressed; - //private static boolean altGrIsPressed = false; - - private static AWTEvent fixNonEnglishKeyboardLayouts(AWTEvent e) { + @NotNull + private static AWTEvent fixNonEnglishKeyboardLayouts(@NotNull AWTEvent e) { if (!(e instanceof KeyEvent)) return e; KeyboardSettingsExternalizable externalizable = KeyboardSettingsExternalizable.getInstance(); @@ -450,9 +446,6 @@ public class IdeEventQueue extends EventQueue { KeyEvent ke = (KeyEvent)e; - // Try to get it from editor - Component sourceComponent = WindowManagerEx.getInstanceEx().getMostRecentFocusedWindow(); - switch (ke.getID()) { case KeyEvent.KEY_PRESSED: break; @@ -479,7 +472,7 @@ public class IdeEventQueue extends EventQueue { // We have a key char. On some non standard layouts it does not correspond to // key code in the event. - Integer keyCodeFromChar = CharToVKeyMap.get(ke.getKeyChar()); + int keyCodeFromChar = CharToVKeyMap.get(ke.getKeyChar()); // Now we have a correct key code as if we'd gotten a KeyEvent for // standard English layout @@ -489,18 +482,14 @@ public class IdeEventQueue extends EventQueue { } // Farther we handle a non standard layout - - if (keyCodeFromChar != null) { - if (keyCodeFromChar != ke.getKeyCode()) { - // non-english layout - ke.setKeyCode(keyCodeFromChar); - } - } + // non-english layout + ke.setKeyCode(keyCodeFromChar); return ke; } - private static AWTEvent mapEvent(AWTEvent e) { + @NotNull + private static AWTEvent mapEvent(@NotNull AWTEvent e) { if (SystemInfo.isXWindow && e instanceof MouseEvent && ((MouseEvent)e).getButton() > 3) { MouseEvent src = (MouseEvent)e; if (src.getButton() < 6) { @@ -520,7 +509,8 @@ public class IdeEventQueue extends EventQueue { return e; } - private AWTEvent mapMetaState(AWTEvent e) { + @NotNull + private AWTEvent mapMetaState(@NotNull AWTEvent e) { if (myWinMetaPressed) { Application app = ApplicationManager.getApplication(); @@ -680,7 +670,7 @@ public class IdeEventQueue extends EventQueue { } } - private static void fixStickyWindow(KeyboardFocusManager mgr, Window wnd, String resetMethod) { + private static void fixStickyWindow(@NotNull KeyboardFocusManager mgr, Window wnd, @NotNull String resetMethod) { if (wnd != null && !wnd.isShowing()) { Window showingWindow = wnd; while (showingWindow != null) { @@ -786,7 +776,7 @@ public class IdeEventQueue extends EventQueue { queue.peekEvent(MouseEvent.MOUSE_CLICKED) != null; } - private void enterSuspendModeIfNeeded(AWTEvent e) { + private void enterSuspendModeIfNeeded(@NotNull AWTEvent e) { if (e instanceof KeyEvent) { if (!mySuspendMode && shallEnterSuspendMode()) { enterSuspendMode(); @@ -798,8 +788,7 @@ public class IdeEventQueue extends EventQueue { return peekEvent(WindowEvent.WINDOW_OPENED) != null; } - private static boolean processAppActivationEvents(AWTEvent e) { - + private static boolean processAppActivationEvents(@NotNull AWTEvent e) { if (e instanceof WindowEvent) { final WindowEvent we = (WindowEvent)e; @@ -811,7 +800,7 @@ public class IdeEventQueue extends EventQueue { return false; } - private static void storeLastFocusedComponent(WindowEvent we) { + private static void storeLastFocusedComponent(@NotNull WindowEvent we) { final Window eventWindow = we.getWindow(); if (we.getID() == WindowEvent.WINDOW_DEACTIVATED || we.getID() == WindowEvent.WINDOW_LOST_FOCUS) { @@ -833,7 +822,7 @@ public class IdeEventQueue extends EventQueue { } } - private void defaultDispatchEvent(final AWTEvent e) { + private void defaultDispatchEvent(@NotNull AWTEvent e) { try { myDispatchingFocusEvent = e instanceof FocusEvent; @@ -850,21 +839,30 @@ public class IdeEventQueue extends EventQueue { } } - private static Field ourStickyAltField; + private static class FieldHolder { + private static final Field ourStickyAltField; + static { + Field field; + try { + Class aClass = Class.forName("com.sun.java.swing.plaf.windows.WindowsRootPaneUI$AltProcessor"); + field = ReflectionUtil.getDeclaredField(aClass, "menuCanceledOnPress"); + } + catch (Exception e) { + field = null; + } + ourStickyAltField = field; + } + } - private static void fixStickyAlt(AWTEvent e) { + private static void fixStickyAlt(@NotNull AWTEvent e) { if (Registry.is("actionSystem.win.suppressAlt.new")) { if (UIUtil.isUnderWindowsLookAndFeel() && e instanceof InputEvent && (((InputEvent)e).getModifiers() & (InputEvent.ALT_MASK | InputEvent.ALT_DOWN_MASK)) != 0 && !(e instanceof KeyEvent && ((KeyEvent)e).getKeyCode() == KeyEvent.VK_ALT)) { try { - if (ourStickyAltField == null) { - Class aClass = Class.forName("com.sun.java.swing.plaf.windows.WindowsRootPaneUI$AltProcessor"); - ourStickyAltField = ReflectionUtil.getDeclaredField(aClass, "menuCanceledOnPress"); - } - if (ourStickyAltField != null) { - ourStickyAltField.set(null, true); + if (FieldHolder.ourStickyAltField != null) { + FieldHolder.ourStickyAltField.set(null, true); } } catch (Exception exception) { @@ -881,7 +879,7 @@ public class IdeEventQueue extends EventQueue { return myDispatchingFocusEvent; } - private static boolean typeAheadDispatchToFocusManager(AWTEvent e) { + private static boolean typeAheadDispatchToFocusManager(@NotNull AWTEvent e) { if (e instanceof KeyEvent) { final KeyEvent event = (KeyEvent)e; if (!event.isConsumed()) { @@ -907,7 +905,7 @@ public class IdeEventQueue extends EventQueue { } } - public void pumpEventsForHierarchy(Component modalComponent, Condition exitCondition) { + public void pumpEventsForHierarchy(Component modalComponent, @NotNull Condition exitCondition) { AWTEvent event; do { try { @@ -940,7 +938,7 @@ public class IdeEventQueue extends EventQueue { @FunctionalInterface public interface EventDispatcher { - boolean dispatch(AWTEvent e); + boolean dispatch(@NotNull AWTEvent e); } private final class MyFireIdleRequest implements Runnable { @@ -948,7 +946,7 @@ public class IdeEventQueue extends EventQueue { private final int myTimeout; - public MyFireIdleRequest(@NotNull Runnable runnable, final int timeout) { + MyFireIdleRequest(@NotNull Runnable runnable, final int timeout) { myTimeout = timeout; myRunnable = runnable; } @@ -976,7 +974,6 @@ public class IdeEventQueue extends EventQueue { } private final class ExitSuspendModeRunnable implements Runnable { - @Override public void run() { if (mySuspendMode) { @@ -991,26 +988,28 @@ public class IdeEventQueue extends EventQueue { } + @NotNull public IdePopupManager getPopupManager() { return myPopupManager; } + @NotNull public IdeKeyEventDispatcher getKeyEventDispatcher() { return myKeyEventDispatcher; } /** - * Same as {@link #blockNextEvents(MouseEvent, IdeEventQueue.BlockMode)} with blockMode equal to COMPLETE. + * Same as {@link #blockNextEvents(MouseEvent, IdeEventQueue.BlockMode)} with {@code blockMode} equal to {@code COMPLETE}. */ - public void blockNextEvents(final MouseEvent e) { + public void blockNextEvents(@NotNull MouseEvent e) { blockNextEvents(e, BlockMode.COMPLETE); } /** - * When blockMode is COMPLETE, blocks following related mouse events completely, when blockMode is - * ACTIONS only blocks performing actions bound to corresponding mouse shortcuts. + * When {@code blockMode} is {@code COMPLETE}, blocks following related mouse events completely, when {@code blockMode} is + * {@code ACTIONS} only blocks performing actions bound to corresponding mouse shortcuts. */ - public void blockNextEvents(final MouseEvent e, BlockMode blockMode) { + public void blockNextEvents(@NotNull MouseEvent e, @NotNull BlockMode blockMode) { myMouseEventDispatcher.blockNextEvents(e, blockMode); } @@ -1027,10 +1026,6 @@ public class IdeEventQueue extends EventQueue { } public void maybeReady() { - flushReady(); - } - - private void flushReady() { if (myReady.isEmpty() || !isReady()) return; Runnable[] ready = myReady.toArray(new Runnable[myReady.size()]); @@ -1041,7 +1036,7 @@ public class IdeEventQueue extends EventQueue { } } - public void doWhenReady(final Runnable runnable) { + public void doWhenReady(@NotNull Runnable runnable) { if (EventQueue.isDispatchThread()) { myReady.add(runnable); maybeReady(); @@ -1064,7 +1059,7 @@ public class IdeEventQueue extends EventQueue { private Robot myRobot; @Override - public boolean dispatch(AWTEvent e) { + public boolean dispatch(@NotNull AWTEvent e) { boolean dispatch = true; if (e instanceof KeyEvent) { KeyEvent ke = (KeyEvent)e; @@ -1121,7 +1116,7 @@ public class IdeEventQueue extends EventQueue { //We have to stop editing with (if any) and consume the event to prevent any further processing (dialog closing etc.) private static class EditingCanceller implements EventDispatcher { @Override - public boolean dispatch(AWTEvent e) { + public boolean dispatch(@NotNull AWTEvent e) { if (e instanceof KeyEvent && e.getID() == KeyEvent.KEY_PRESSED && ((KeyEvent)e).getKeyCode() == KeyEvent.VK_ESCAPE) { final Component owner = UIUtil.findParentByCondition(KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(), component -> component instanceof JTable || component instanceof JTree); @@ -1143,7 +1138,7 @@ public class IdeEventQueue extends EventQueue { return !SystemInfo.isMac || myInputMethodLock == 0; } - public void disableInputMethods(Disposable parentDisposable) { + public void disableInputMethods(@NotNull Disposable parentDisposable) { myInputMethodLock++; Disposer.register(parentDisposable, () -> myInputMethodLock--); } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java index 9798128c8fb8..5275b93d247d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeMouseEventDispatcher.java @@ -31,10 +31,12 @@ import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.impl.FocusManagerImpl; import com.intellij.openapi.wm.impl.IdeGlassPaneImpl; +import com.intellij.ui.components.JBScrollPane; import com.intellij.util.ReflectionUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.ui.UIUtil; import org.intellij.lang.annotations.JdkConstants; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -46,7 +48,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import static com.intellij.ui.components.JBScrollPane.isScrollEvent; import static java.awt.event.MouseEvent.*; /** @@ -136,9 +137,9 @@ public final class IdeMouseEventDispatcher { } /** - * @return true if and only if the passed event is already dispatched by the - * IdeMouseEventDispatcher and there is no need for any other processing of the event. - * If the method returns false then it means that the event should be delivered + * @return {@code true} if and only if the passed event is already dispatched by the + * {@code IdeMouseEventDispatcher} and there is no need for any other processing of the event. + * If the method returns {@code false} then it means that the event should be delivered * to normal event dispatching. */ public boolean dispatchMouseEvent(MouseEvent e) { @@ -310,7 +311,7 @@ public final class IdeMouseEventDispatcher { FeatureUsageTracker.getInstance().triggerFeatureUsed("ui.horizontal.scrolling"); myLastHorScrolledComponentHash = scrollBar.hashCode(); } - scrollBar.setValue(scrollBar.getValue() + getScrollAmount(c, me, scrollBar)); + scrollBar.setValue(scrollBar.getValue() + getScrollAmount(me, scrollBar)); return true; } return false; @@ -320,7 +321,7 @@ public final class IdeMouseEventDispatcher { myLastHorScrolledComponentHash = 0; } - private static int getScrollAmount(Component c, MouseWheelEvent me, JScrollBar scrollBar) { + private static int getScrollAmount(MouseWheelEvent me, JScrollBar scrollBar) { return me.getUnitsToScroll() * scrollBar.getUnitIncrement(); } @@ -331,7 +332,7 @@ public final class IdeMouseEventDispatcher { final MouseWheelEvent mwe = (MouseWheelEvent)e; return mwe.isShiftDown() && mwe.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL - && isScrollEvent(mwe) + && JBScrollPane.isScrollEvent(mwe) && findHorizontalScrollBar(c) != null; } return false; @@ -363,7 +364,7 @@ public final class IdeMouseEventDispatcher { return c != null && "y.view.Graph2DView".equals(c.getClass().getName()); } - public void blockNextEvents(final MouseEvent e, IdeEventQueue.BlockMode blockMode) { + public void blockNextEvents(@NotNull MouseEvent e, @NotNull IdeEventQueue.BlockMode blockMode) { final JRootPane root = findRoot(e); if (root == null) return; diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 1290f2bf384c..188fbb36a54d 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -248,7 +248,7 @@ action.Compare.Selected.text=_Compare with... group.NewGroup.text=_New group.WeighingNewGroup.text=_New action.NewClass.text=Java Class -action.NewFile.text=File +action.NewFile.text=File... action.NewDir.text=Directory/Package action.NewFromTemplate.text=From Template action.Diff.ShowDiff.text=Show Diff @@ -615,7 +615,7 @@ action.Unscramble.text=Analyze _Stacktrace... action.Unscramble.description=Open console with the navigatable stacktrace action.IdeScriptingConsole.text=IDE Scripting Console action.IdeScriptingConsole.description=Open IDE scripting console -action.NewScratchFile.text=New Scratch File... +action.NewScratchFile.text=Scratch File... action.NewScratchFile.description=Creates new scratch file with chosen language action.NewScratchBuffer.text=New Scratch Buffer action.NewScratchBuffer.description=Creates new or reuses existing scratch buffer diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 8dc8b726962c..e9369d92509a 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -369,8 +369,8 @@ prompt.enter.new.directory.name=Enter new directory name: prompt.enter.new.package.name=Enter new package name: title.new.directory=New Directory title.new.package=New Package -action.package=Package -action.directory=Directory +action.package=Package... +action.directory=Directory... error.name.should.be.specified=A name should be specified progress.creating.directory=Creating directory {0}{1}{2} progress.creating.package=Creating package {0}.{1} diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index f32e0526ba96..79fc2e5f0658 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -370,7 +370,6 @@ - @@ -385,6 +384,7 @@ + diff --git a/platform/testFramework/src/com/intellij/mock/MockFileTypeManager.java b/platform/testFramework/src/com/intellij/mock/MockFileTypeManager.java index 673dd6a5378f..6b576e61ede0 100644 --- a/platform/testFramework/src/com/intellij/mock/MockFileTypeManager.java +++ b/platform/testFramework/src/com/intellij/mock/MockFileTypeManager.java @@ -155,8 +155,9 @@ public class MockFileTypeManager extends FileTypeManagerEx { @Override @NotNull public FileType getStdFileType(@NotNull @NonNls final String fileTypeName) { - if ("ARCHIVE".equals(fileTypeName) || "CLASS".equals(fileTypeName)) return UnknownFileType.INSTANCE; + if ("ARCHIVE".equals(fileTypeName)) return UnknownFileType.INSTANCE; if ("PLAIN_TEXT".equals(fileTypeName)) return PlainTextFileType.INSTANCE; + if ("CLASS".equals(fileTypeName)) return loadFileTypeSafe("com.intellij.ide.highlighter.JavaClassFileType", fileTypeName); if ("JAVA".equals(fileTypeName)) return loadFileTypeSafe("com.intellij.ide.highlighter.JavaFileType", fileTypeName); if ("XML".equals(fileTypeName)) return loadFileTypeSafe("com.intellij.ide.highlighter.XmlFileType", fileTypeName); if ("DTD".equals(fileTypeName)) return loadFileTypeSafe("com.intellij.ide.highlighter.DTDFileType", fileTypeName); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index e337a472ee45..cae84db238e3 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -135,9 +135,8 @@ import java.util.*; public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsightTestFixture { private static final Function INTENTION_NAME_FUN = intentionAction -> "\"" + intentionAction.getText() + "\""; - private static final String START_FOLD = ""; - private static final String END_FOLD = ""; private static final String RAINBOW = "rainbow"; + private static final String FOLD = "fold"; private final IdeaProjectTestFixture myProjectFixture; private final TempDirTestFixture myTempDirFixture; @@ -1632,52 +1631,34 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig @NotNull public String getFoldingDescription(boolean withCollapseStatus) { CodeFoldingManager.getInstance(getProject()).buildInitialFoldings(myEditor); - - final FoldingModel model = myEditor.getFoldingModel(); - final FoldRegion[] foldingRegions = model.getAllFoldRegions(); - final List borders = new LinkedList<>(); - - for (FoldRegion region : foldingRegions) { - borders.add(new Border(Border.LEFT, region.getStartOffset(), region.getPlaceholderText(), region.isExpanded())); - borders.add(new Border(Border.RIGHT, region.getEndOffset(), "", region.isExpanded())); - } - Collections.sort(borders); - - StringBuilder result = new StringBuilder(myEditor.getDocument().getText()); - for (Border border : borders) { - result.insert(border.getOffset(), border.isSide() == Border.LEFT ? "" : END_FOLD); - } - - return result.toString(); + return getTagsFromSegments(myEditor.getDocument().getText(), + Arrays.asList(myEditor.getFoldingModel().getAllFoldRegions()), + FOLD, + foldRegion -> "text=\'" + foldRegion.getPlaceholderText() + "\'" + + (withCollapseStatus ? (" expand=\'" + foldRegion.isExpanded() + "\'") : "")); } @NotNull - public String getHighlightingDescription(@NotNull List highlighting, @NotNull String tagName, boolean withColor) { + public static String getTagsFromSegments(@NotNull String text, + @NotNull Collection segments, + @NotNull String tagName, + @Nullable Function attrCalculator) { final List borders = new LinkedList<>(); - for (HighlightInfo region : highlighting) { - TextAttributes attributes = region.getTextAttributes(null, null); - borders.add(new Border(Border.LEFT, region.getStartOffset(), - attributes == null ? "null" - : attributes.getForegroundColor() == null - ? "null" - : Integer.toHexString(attributes.getForegroundColor().getRGB()), - false)); - borders.add(new Border(Border.RIGHT, region.getEndOffset(), "", false)); + for (T region : segments) { + String attr = attrCalculator == null ? null : attrCalculator.fun(region); + borders.add(new CodeInsightTestFixtureImpl.Border(true, region.getStartOffset(),attr)); + borders.add(new CodeInsightTestFixtureImpl.Border(false, region.getEndOffset(), "")); } Collections.sort(borders); - StringBuilder result = new StringBuilder(myEditor.getDocument().getText()); - for (Border border : borders) { + StringBuilder result = new StringBuilder(text); + for (CodeInsightTestFixtureImpl.Border border : borders) { StringBuilder info = new StringBuilder(); info.append('<'); - if (border.isSide() == Border.LEFT) { + if (border.isLeftBorder()) { info.append(tagName); - if (withColor) { - info.append(" color=\'").append(border.myText).append('\''); + if (border.myText != null) { + info.append(' ').append(border.myText); } } else { @@ -1686,7 +1667,6 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig info.append('>'); result.insert(border.getOffset(), info); } - return result.toString(); } @@ -1701,7 +1681,8 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig Assert.assertNotNull(expectedContent); expectedContent = StringUtil.replace(expectedContent, "\r", ""); - final String cleanContent = expectedContent.replaceAll(START_FOLD, "").replaceAll(END_FOLD, ""); + final String cleanContent = expectedContent.replaceAll("<" + FOLD + "\\stext=\'[^\']*\'(\\sexpand=\'[^\']*\')*>", "") + .replace("", ""); if (destinationFileName == null) { configureByText(FileTypeManager.getInstance().getFileTypeByFileName(verificationFileName), cleanContent); } @@ -1741,9 +1722,19 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig RainbowHighlighter.setRainbowEnabled(globalScheme, null, isRainbowOn); configureByText(fileName, text.replaceAll("<" + RAINBOW + "(\\scolor=\'[^\']*\')?>", "").replace("", "")); - Assert.assertEquals(text, getHighlightingDescription(ContainerUtil.filter(doHighlighting(), - info -> info.type == RainbowHighlighter.RAINBOW_ELEMENT), RAINBOW, - withColor)); + List highlighting = ContainerUtil.filter(doHighlighting(), + info -> info.type == RainbowHighlighter.RAINBOW_ELEMENT); + Assert.assertEquals(text, getTagsFromSegments(myEditor.getDocument().getText(), highlighting, RAINBOW, highlightInfo -> { + if (!withColor) { + return null; + } + TextAttributes attributes = highlightInfo.getTextAttributes(null, null); + String color = attributes == null ? "null" + : attributes.getForegroundColor() == null + ? "null" + : Integer.toHexString(attributes.getForegroundColor().getRGB()); + return "color=\'" + color + "\'"; + })); } finally { RainbowHighlighter.setRainbowEnabled(globalScheme, null, isRainbowOnInScheme); @@ -1844,26 +1835,18 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig } private static class Border implements Comparable { - private static final boolean LEFT = true; - private static final boolean RIGHT = false; - private final boolean mySide; + private final boolean myIsLeftBorder; private final int myOffset; private final String myText; - private final boolean myIsExpanded; - private Border(boolean side, int offset, String text, boolean isExpanded) { - mySide = side; + private Border(boolean isLeftBorder, int offset, String text) { + myIsLeftBorder = isLeftBorder; myOffset = offset; myText = text; - myIsExpanded = isExpanded; } - public boolean isExpanded() { - return myIsExpanded; - } - - public boolean isSide() { - return mySide; + public boolean isLeftBorder() { + return myIsLeftBorder; } public int getOffset() { diff --git a/platform/util/src/com/intellij/openapi/util/IconLoader.java b/platform/util/src/com/intellij/openapi/util/IconLoader.java index f0a712740bcd..11fce1dac5b5 100644 --- a/platform/util/src/com/intellij/openapi/util/IconLoader.java +++ b/platform/util/src/com/intellij/openapi/util/IconLoader.java @@ -16,7 +16,6 @@ package com.intellij.openapi.util; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.reference.SoftReference; import com.intellij.ui.RetrievableIcon; @@ -363,7 +362,7 @@ public final class IconLoader { return icon; } - private static final class CachedImageIcon extends JBUI.ValidatingScalableJBIcon { + private static final class CachedImageIcon extends JBUI.AuxScalableJBIcon { private volatile Object myRealIcon; private String myOriginalPath; private ClassLoader myClassLoader; @@ -383,12 +382,12 @@ public final class IconLoader { @NotNull private synchronized ImageIcon getRealIcon() { - if (isLoaderDisabled() && (myRealIcon == null || dark != USE_DARK_ICONS || !isJBUIScaleValid() || filter != IMAGE_FILTER || numberOfPatchers != ourPatchers.size())) return EMPTY_ICON; + if (isLoaderDisabled() && (myRealIcon == null || dark != USE_DARK_ICONS || needUpdateJBUIScale() || filter != IMAGE_FILTER || numberOfPatchers != ourPatchers.size())) return EMPTY_ICON; if (!isValid()) { myRealIcon = null; dark = USE_DARK_ICONS; - validateJBUIScale(); + updateJBUIScale(); filter = IMAGE_FILTER; myScaledIconsCache.clear(); if (numberOfPatchers != ourPatchers.size()) { @@ -433,7 +432,7 @@ public final class IconLoader { } private boolean isValid() { - return dark == USE_DARK_ICONS && isJBUIScaleValid() && filter == IMAGE_FILTER && numberOfPatchers == ourPatchers.size(); + return dark == USE_DARK_ICONS && !needUpdateJBUIScale() && filter == IMAGE_FILTER && numberOfPatchers == ourPatchers.size(); } @Override @@ -526,7 +525,7 @@ public final class IconLoader { } } - public abstract static class LazyIcon extends JBUI.ValidatingScalableJBIcon { + public abstract static class LazyIcon extends JBUI.AuxScalableJBIcon { private boolean myWasComputed; private Icon myIcon; private boolean isDarkVariant = USE_DARK_ICONS; @@ -554,9 +553,9 @@ public final class IconLoader { } protected final synchronized Icon getOrComputeIcon() { - if (!myWasComputed || isDarkVariant != USE_DARK_ICONS || !isJBUIScaleValid() || filter != IMAGE_FILTER || numberOfPatchers != ourPatchers.size()) { + if (!myWasComputed || isDarkVariant != USE_DARK_ICONS || needUpdateJBUIScale() || filter != IMAGE_FILTER || numberOfPatchers != ourPatchers.size()) { isDarkVariant = USE_DARK_ICONS; - validateJBUIScale(); + updateJBUIScale(); filter = IMAGE_FILTER; myWasComputed = true; numberOfPatchers = ourPatchers.size(); diff --git a/platform/util/src/com/intellij/util/ui/JBUI.java b/platform/util/src/com/intellij/util/ui/JBUI.java index 77a66c43143f..8b66f31ca2cb 100644 --- a/platform/util/src/com/intellij/util/ui/JBUI.java +++ b/platform/util/src/com/intellij/util/ui/JBUI.java @@ -294,23 +294,23 @@ public class JBUI { private float myInitialJBUIScale = scale(1f); /** - * @return the scale factor aligning the icon size metrics to conform to JBUI.scale + * @return the scale factor aligning the icon size metrics to conform to up-to-date JBUI.scale */ - private float getAligningJBUIScale() { - return (myInitialJBUIScale == scale(1f)) ? 1f : scale(1f) / myInitialJBUIScale; + private float getAligningScale() { + return scale(1f) / myInitialJBUIScale; } /** * @return whether the icon size metrics are pre-scaled or not */ - public boolean isPreScaled() { + protected boolean isPreScaled() { return myInitialJBUIScale != 1f; } /** * Sets the icon size metrics to {@code preScaled} */ - public void setPreScaled(boolean preScaled) { + protected void setPreScaled(boolean preScaled) { myInitialJBUIScale = preScaled ? scale(1f) : 1f; } @@ -335,7 +335,7 @@ public class JBUI { * Scales the value to conform to JBUI.scale */ public float scaleVal(float value) { - return value * getAligningJBUIScale(); + return value * getAligningScale(); } } @@ -366,7 +366,16 @@ public class JBUI { return scaleVal(value, Scale.EFFECTIVE); } + @Override + public float scaleVal(float value) { + return scaleVal(value, Scale.EFFECTIVE); + } + public int scaleVal(int value, Scale type) { + return (int)scaleVal((float)value, type); + } + + public float scaleVal(float value, Scale type) { switch (type) { case JBUI: return super.scaleVal(value); @@ -386,27 +395,28 @@ public class JBUI { } /** - * A ScalableJBIcon validating JBUI.scale change on demand. + * A ScalableJBIcon caching JBUI.scale and allowing to lazily track its change. * * @author tav */ - public static abstract class ValidatingScalableJBIcon extends ScalableJBIcon { + public static abstract class AuxScalableJBIcon extends ScalableJBIcon { private float myCachedJBUIScale = JBUI.scale(1f); /** * @return cached JBUI.scale */ - public float getJBUIScale() { + protected float getJBUIScale() { return myCachedJBUIScale; } /** - * Validates cached JBUI.scale + * Checks if cached JBUI.scale should be updated and updates it. + * Use {@link #scaleVal(int, Scale)} to update the icon size metrics. * - * @return true if cached JBUI.scale was invalid (and the icon size metrics should be updated) + * @return true if cached JBUI.scale was updated */ - public boolean validateJBUIScale() { - if (!isJBUIScaleValid()) { + protected boolean updateJBUIScale() { + if (needUpdateJBUIScale()) { myCachedJBUIScale = JBUI.scale(1f); return true; } @@ -414,9 +424,9 @@ public class JBUI { } /** - * @return true if cached JBUI.scale is valid + * @return true if cached JBUI.scale should be updated */ - public boolean isJBUIScaleValid() { + protected boolean needUpdateJBUIScale() { return myCachedJBUIScale == JBUI.scale(1f); } } diff --git a/platform/util/src/com/intellij/util/ui/MouseEventAdapter.java b/platform/util/src/com/intellij/util/ui/MouseEventAdapter.java index f7c7b4745d24..7be1b6ce0388 100644 --- a/platform/util/src/com/intellij/util/ui/MouseEventAdapter.java +++ b/platform/util/src/com/intellij/util/ui/MouseEventAdapter.java @@ -15,7 +15,9 @@ */ package com.intellij.util.ui; -import javax.swing.SwingUtilities; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; import javax.swing.event.MenuDragMouseEvent; import javax.swing.event.MouseInputListener; import java.awt.*; @@ -91,25 +93,30 @@ public class MouseEventAdapter extends MouseAdapter implements MouseInputList return adapter instanceof MouseWheelListener ? (MouseWheelListener)adapter : null; } - protected MouseEvent convert(MouseEvent event) { + @NotNull + protected MouseEvent convert(@NotNull MouseEvent event) { return event; } - protected MouseWheelEvent convert(MouseWheelEvent event) { + @NotNull + protected MouseWheelEvent convert(@NotNull MouseWheelEvent event) { return event; } - public static MouseEvent convert(MouseEvent event, Component source) { + @NotNull + public static MouseEvent convert(@NotNull MouseEvent event, Component source) { Point point = event.getLocationOnScreen(); SwingUtilities.convertPointFromScreen(point, source); return convert(event, source, point.x, point.y); } - public static MouseEvent convert(MouseEvent event, Component source, int x, int y) { + @NotNull + public static MouseEvent convert(@NotNull MouseEvent event, Component source, int x, int y) { return convert(event, source, event.getID(), event.getWhen(), event.getModifiers() | event.getModifiersEx(), x, y); } - public static MouseEvent convert(MouseEvent event, Component source, int id, long when, int modifiers, int x, int y) { + @NotNull + public static MouseEvent convert(@NotNull MouseEvent event, Component source, int id, long when, int modifiers, int x, int y) { if (event instanceof MouseWheelEvent) return convert((MouseWheelEvent)event, source, id, when, modifiers, x, y); if (event instanceof MenuDragMouseEvent) return convert((MenuDragMouseEvent)event, source, id, when, modifiers, x, y); return new MouseEvent(source, id, when, modifiers, x, y, @@ -118,7 +125,8 @@ public class MouseEventAdapter extends MouseAdapter implements MouseInputList event.getButton()); } - public static MouseWheelEvent convert(MouseWheelEvent event, Component source, int id, long when, int modifiers, int x, int y) { + @NotNull + public static MouseWheelEvent convert(@NotNull MouseWheelEvent event, Component source, int id, long when, int modifiers, int x, int y) { return new MouseWheelEvent(source, id, when, modifiers, x, y, event.getXOnScreen(), event.getYOnScreen(), @@ -129,6 +137,7 @@ public class MouseEventAdapter extends MouseAdapter implements MouseInputList event.getWheelRotation()); } + @NotNull public static MenuDragMouseEvent convert(MenuDragMouseEvent event, Component source, int id, long when, int modifiers, int x, int y) { return new MenuDragMouseEvent(source, id, when, modifiers, x, y, event.getClickCount(), diff --git a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java index 568348118ca3..c9c8659a2f71 100644 --- a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java +++ b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java @@ -98,8 +98,9 @@ public class WideSelectionTreeUI extends BasicTreeUI { } } + @NotNull @Override - protected MouseEvent convert(MouseEvent event) { + protected MouseEvent convert(@NotNull MouseEvent event) { if (!event.isConsumed() && SwingUtilities.isLeftMouseButton(event)) { int x = event.getX(); int y = event.getY(); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogTabsProperties.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogTabsProperties.java index 476b03585932..08a53b42111b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogTabsProperties.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogTabsProperties.java @@ -50,7 +50,12 @@ public class VcsLogTabsProperties implements PersistentStateComponent refs = cell.getRefsToThisCommit(); if (!refs.isEmpty()) { diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java index 2a4f207481f0..91814dfbb71a 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java @@ -21,7 +21,6 @@ import com.intellij.openapi.application.Result; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings; -import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListenerAdapter; import com.intellij.openapi.externalSystem.test.ExternalSystemImportingTestCase; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; @@ -37,17 +36,21 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.IdeaTestUtil; import com.intellij.util.PathUtil; import com.intellij.util.containers.ContainerUtil; +import org.gradle.StartParameter; import org.gradle.util.GradleVersion; import org.gradle.wrapper.GradleWrapperMain; +import org.gradle.wrapper.PathAssembler; +import org.gradle.wrapper.WrapperConfiguration; import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.gradle.tooling.VersionMatcherRule; import org.jetbrains.plugins.gradle.settings.DistributionType; import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; import org.jetbrains.plugins.gradle.settings.GradleSettings; +import org.jetbrains.plugins.gradle.tooling.VersionMatcherRule; import org.jetbrains.plugins.gradle.tooling.builder.AbstractModelBuilderTest; import org.jetbrains.plugins.gradle.util.GradleConstants; +import org.jetbrains.plugins.gradle.util.GradleUtil; import org.junit.Rule; import org.junit.rules.TestName; import org.junit.runner.RunWith; @@ -62,6 +65,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Properties; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; import static org.jetbrains.plugins.gradle.tooling.builder.AbstractModelBuilderTest.DistributionLocator; import static org.jetbrains.plugins.gradle.tooling.builder.AbstractModelBuilderTest.SUPPORTED_GRADLE_VERSIONS; @@ -240,6 +245,20 @@ public abstract class GradleImportingTestCase extends ExternalSystemImportingTes properties.store(writer, null); createProjectSubFile("gradle/wrapper/gradle-wrapper.properties", writer.toString()); + + WrapperConfiguration wrapperConfiguration = GradleUtil.getWrapperConfiguration(getProjectPath()); + PathAssembler.LocalDistribution localDistribution = new PathAssembler( + StartParameter.DEFAULT_GRADLE_USER_HOME).getDistribution(wrapperConfiguration); + + File zip = localDistribution.getZipFile(); + try { + ZipFile zipFile = new ZipFile(zip); + zipFile.close(); + } + catch (ZipException e) { + System.out.println("Corrupted file will be removed: " + zip.getPath()); + e.printStackTrace(); + } } @NotNull diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/config/DefaultGroovyFrameworkConfigNotification.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/config/DefaultGroovyFrameworkConfigNotification.java index 6e4f33de4c44..4cc8e6c0ab6f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/config/DefaultGroovyFrameworkConfigNotification.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/config/DefaultGroovyFrameworkConfigNotification.java @@ -16,12 +16,13 @@ package org.jetbrains.plugins.groovy.config; import com.intellij.openapi.module.Module; -import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.ui.configuration.libraries.AddCustomLibraryDialog; +import com.intellij.psi.JavaPsiFacade; import com.intellij.ui.EditorNotificationPanel; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.annotator.GroovyFrameworkConfigNotification; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; /** * @author sergey.evdokimov @@ -35,8 +36,9 @@ public class DefaultGroovyFrameworkConfigNotification extends GroovyFrameworkCon @Override public boolean hasFrameworkLibrary(@NotNull Module module) { - final Library[] libraries = GroovyConfigUtils.getInstance().getSDKLibrariesByModule(module); - return libraries.length > 0; + return JavaPsiFacade.getInstance(module.getProject()).findClass( + GroovyCommonClassNames.GROOVY_OBJECT, module.getModuleWithDependenciesAndLibrariesScope(true) + ) != null; } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java index 60d774a76f4c..0990ad551ad9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java @@ -286,7 +286,8 @@ public abstract class MvcFramework { } public PathsList getApplicationClassPath(Module module) { - final List classPath = OrderEnumerator.orderEntries(module).recursively().withoutSdk().getPathsList().getVirtualFiles(); + final List classPath = ContainerUtil.newArrayList(); + classPath.addAll(OrderEnumerator.orderEntries(module).recursively().withoutSdk().getPathsList().getVirtualFiles()); retainOnlyJarsAndDirectories(classPath); diff --git a/python/helpers/pycharm_generator_utils/util_methods.py b/python/helpers/pycharm_generator_utils/util_methods.py index bd5bd7ba7ebd..42451811389c 100644 --- a/python/helpers/pycharm_generator_utils/util_methods.py +++ b/python/helpers/pycharm_generator_utils/util_methods.py @@ -190,9 +190,6 @@ class __coroutine(object): def __await__(self): return [] - def __iter__(self): - return [] - def close(self): pass diff --git a/python/helpers/python-skeletons/builtins.py b/python/helpers/python-skeletons/builtins.py index 69680d5290ea..41126a7322c5 100644 --- a/python/helpers/python-skeletons/builtins.py +++ b/python/helpers/python-skeletons/builtins.py @@ -2455,12 +2455,6 @@ class __coroutine(object): """ return [] - def __iter__(self): - """ - :rtype: collections.Iterable[unknown] - """ - return [] - def close(self): """ :rtype: None diff --git a/python/ipnb/resources/META-INF/ipython-notebook.xml b/python/ipnb/resources/META-INF/ipython-notebook.xml index ea2ac8ca0acf..1dbc44eb4753 100644 --- a/python/ipnb/resources/META-INF/ipython-notebook.xml +++ b/python/ipnb/resources/META-INF/ipython-notebook.xml @@ -19,6 +19,7 @@ + - + @@ -44,6 +44,20 @@ + + + + + + + + + + + + + + diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConfigurable.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConfigurable.java index 2eb1a4536204..8ee52ff91456 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConfigurable.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConfigurable.java @@ -17,6 +17,7 @@ public class IpnbConfigurable implements SearchableConfigurable { private JPanel myMainPanel; private JBTextField myFieldUrl; private TextFieldWithBrowseButton myWorkingDirField; + private JBTextField myArgumentsField; @NotNull private final Project myProject; public IpnbConfigurable(@NotNull Project project) { @@ -26,6 +27,7 @@ public class IpnbConfigurable implements SearchableConfigurable { myWorkingDirField.addBrowseFolderListener("Select Working Directory", null, myProject, fileChooserDescriptor); myFieldUrl.setText(IpnbSettings.getInstance(myProject).getURL()); myWorkingDirField.setText(IpnbSettings.getInstance(myProject).getWorkingDirectory()); + myArgumentsField.setText(IpnbSettings.getInstance(myProject).getArguments()); } @Nls @@ -47,11 +49,14 @@ public class IpnbConfigurable implements SearchableConfigurable { @Override public boolean isModified() { final String oldUrl = IpnbSettings.getInstance(myProject).getURL(); - final String url = StringUtil.trimEnd(StringUtil.notNullize(myFieldUrl.getText()), "/"); - final String oldWorkingDirectory = StringUtil.notNullize(IpnbSettings.getInstance(myProject).getWorkingDirectory()); + final String oldArguments = StringUtil.notNullize(IpnbSettings.getInstance(myProject).getArguments()); + + final String url = StringUtil.trimEnd(StringUtil.notNullize(myFieldUrl.getText()), "/"); final String workingDirectory = StringUtil.notNullize(myWorkingDirField.getText()); - return !url.equals(oldUrl) || !workingDirectory.equals(oldWorkingDirectory); + final String arguments = StringUtil.notNullize(myArgumentsField.getText()); + + return !url.equals(oldUrl) || !workingDirectory.equals(oldWorkingDirectory) || !arguments.equals(oldArguments); } @Override @@ -60,12 +65,14 @@ public class IpnbConfigurable implements SearchableConfigurable { url = StringUtil.trimEnd(url, "/"); IpnbSettings.getInstance(myProject).setURL(url); IpnbSettings.getInstance(myProject).setWorkingDirectory(myWorkingDirField.getText()); + IpnbSettings.getInstance(myProject).setArguments(myArgumentsField.getText()); } @Override public void reset() { myFieldUrl.setText(IpnbSettings.getInstance(myProject).getURL()); myWorkingDirField.setText(IpnbSettings.getInstance(myProject).getWorkingDirectory()); + myArgumentsField.setText(IpnbSettings.getInstance(myProject).getArguments()); } @Override diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java index b6bb566986c6..27ca1cadd728 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java @@ -43,7 +43,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.ipnb.editor.IpnbFileEditor; import org.jetbrains.plugins.ipnb.editor.panels.code.IpnbCodePanel; import org.jetbrains.plugins.ipnb.format.IpnbParser; -import org.jetbrains.plugins.ipnb.format.cells.output.IpnbOutputCell; import org.jetbrains.plugins.ipnb.protocol.IpnbConnection; import org.jetbrains.plugins.ipnb.protocol.IpnbConnectionListenerBase; import org.jetbrains.plugins.ipnb.protocol.IpnbConnectionV3; @@ -164,7 +163,7 @@ public final class IpnbConnectionManager implements ProjectComponent { final IpnbCodePanel cell = myUpdateMap.get(parentMessageId); cell.getCell().setPromptNumber(connection.getExecCount()); //noinspection unchecked - cell.updatePanel(null, (List)connection.getOutput().clone()); + cell.updatePanel(null, connection.getOutput()); } @Override @@ -175,6 +174,14 @@ public final class IpnbConnectionManager implements ProjectComponent { cell.updatePanel(payload, null); } } + + @Override + public void onFinished(@NotNull IpnbConnection connection, @NotNull String parentMessageId) { + if (!myUpdateMap.containsKey(parentMessageId)) return; + final IpnbCodePanel cell = myUpdateMap.remove(parentMessageId); + cell.getCell().setPromptNumber(connection.getExecCount()); + cell.finishExecution(); + } }; try { @@ -265,7 +272,8 @@ public final class IpnbConnectionManager implements ProjectComponent { String url = showDialogUrl(initUrl); if (url == null) return false; - IpnbSettings.getInstance(myProject).setURL(url); + final IpnbSettings ipnbSettings = IpnbSettings.getInstance(myProject); + ipnbSettings.setURL(url); final Pair hostPort = getHostPortFromUrl(url); if (hostPort == null) { @@ -303,7 +311,12 @@ public final class IpnbConnectionManager implements ProjectComponent { parameters.add("--port"); parameters.add(hostPort.getSecond()); } - final String directory = IpnbSettings.getInstance(myProject).getWorkingDirectory(); + final String arguments = ipnbSettings.getArguments(); + if (!StringUtil.isEmptyOrSpaces(arguments)) { + parameters.addAll(StringUtil.split(arguments, " ")); + } + + final String directory = ipnbSettings.getWorkingDirectory(); final String baseDir = !StringUtil.isEmptyOrSpaces(directory) ? directory : ModuleRootManager.getInstance(module).getContentRoots()[0].getCanonicalPath(); final GeneralCommandLine commandLine = new GeneralCommandLine(parameters).withWorkDirectory(baseDir); diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbSettings.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbSettings.java index 3806ef7deaec..91e13963f34f 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbSettings.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbSettings.java @@ -14,6 +14,7 @@ public class IpnbSettings implements PersistentStateComponent { public static final String DEFAULT_URL = "http://127.0.0.1:8888"; public String URL = DEFAULT_URL; private String myWorkingDirectory; + private String myArguments; public static IpnbSettings getInstance(@NotNull Project project) { return ServiceManager.getService(project, IpnbSettings.class); @@ -37,6 +38,14 @@ public class IpnbSettings implements PersistentStateComponent { return myWorkingDirectory; } + public String getArguments() { + return myArguments; + } + + public void setArguments(String arguments) { + myArguments = arguments; + } + @Override public IpnbSettings getState() { return this; diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbEditorUtil.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbEditorUtil.java index 336a41c767f1..7ac3bc26bb31 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbEditorUtil.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/IpnbEditorUtil.java @@ -105,7 +105,7 @@ public class IpnbEditorUtil { } } - public static JComponent createPromptComponent(@Nullable Integer promptNumber, @NotNull final PromptType type) { + public static JLabel createPromptComponent(@Nullable Integer promptNumber, @NotNull final PromptType type) { final String promptText = prompt(promptNumber, type); JLabel promptLabel = new JLabel(promptText); promptLabel.setHorizontalAlignment(SwingConstants.RIGHT); @@ -120,7 +120,7 @@ public class IpnbEditorUtil { return promptLabel; } - protected static String prompt(@Nullable Integer promptNumber, @NotNull final PromptType type) { + public static String prompt(@Nullable Integer promptNumber, @NotNull final PromptType type) { if (type == PromptType.In) { return promptNumber == null ? type + " [ ]:" : promptNumber > 0 ? String.format(type + " [%d]:", promptNumber) : type + " [*]:"; } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/actions/IpnbMoveCellDownAction.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/actions/IpnbMoveCellDownAction.java index d1e6ba932def..987c5daf09c9 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/actions/IpnbMoveCellDownAction.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/actions/IpnbMoveCellDownAction.java @@ -19,15 +19,8 @@ public class IpnbMoveCellDownAction extends AnAction { final FileEditor editor = PlatformDataKeys.FILE_EDITOR.getData(context); if (editor instanceof IpnbFileEditor) { final IpnbFilePanel ipnbFilePanel = ((IpnbFileEditor)editor).getIpnbFilePanel(); - CommandProcessor.getInstance().executeCommand(ipnbFilePanel.getProject(), new Runnable() { - public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - ipnbFilePanel.moveCell(true); - } - }); - } - }, "Ipnb.moveCell", new Object()); + CommandProcessor.getInstance().executeCommand(ipnbFilePanel.getProject(), () -> ApplicationManager.getApplication().runWriteAction( + () -> ipnbFilePanel.moveCell(true)), "Ipnb.moveCell", new Object()); } } } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbEditablePanel.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbEditablePanel.java index 01fd4092e342..0bef909c4459 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbEditablePanel.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/editor/panels/IpnbEditablePanel.java @@ -33,10 +33,10 @@ public abstract class IpnbEditablePanel { } setSecondComponent(myOutputComponent); } - + public void hideOutputPanel() { setOutputStateInCell(true); setFirstComponent(myToggleBar); setSecondComponent(null); } } - + @NotNull private JPanel createCodeComponent() { myCodeSourcePanel = new IpnbCodeSourcePanel(myProject, this, myCell); - final JPanel panel = new JPanel(new GridBagLayout()); panel.setBackground(IpnbEditorUtil.getBackground()); addPromptPanel(panel, myCell.getPromptNumber(), IpnbEditorUtil.PromptType.In, myCodeSourcePanel); @@ -143,13 +142,13 @@ public class IpnbCodePanel extends IpnbEditablePanel { outputPanel.setBackground(IpnbEditorUtil.getBackground()); for (IpnbOutputCell outputCell : myCell.getCellOutputs()) { - addOutputPanel(outputPanel, outputCell, this, true); + addOutputPanel(outputPanel, outputCell, true); } return outputPanel; } - + public void hideOutputPanel() { myHideableOutputPanel.hideOutputPanel(); @@ -208,33 +207,33 @@ public class IpnbCodePanel extends IpnbEditablePanel { } private void addOutputPanel(@NotNull final JComponent mainPanel, - @NotNull final IpnbOutputCell outputCell, IpnbCodePanel ipnbCodePanel, boolean addPrompt) { + @NotNull final IpnbOutputCell outputCell, boolean addPrompt) { final IpnbEditorUtil.PromptType promptType = addPrompt ? IpnbEditorUtil.PromptType.Out : IpnbEditorUtil.PromptType.None; final JPanel panel = new JPanel(new GridBagLayout()); panel.setBackground(IpnbEditorUtil.getBackground()); if (outputCell instanceof IpnbImageOutputCell) { addPromptPanel(panel, myCell.getPromptNumber(), promptType, - new IpnbImagePanel((IpnbImageOutputCell)outputCell, ipnbCodePanel)); + new IpnbImagePanel((IpnbImageOutputCell)outputCell, this)); } else if (outputCell instanceof IpnbHtmlOutputCell) { addPromptPanel(panel, myCell.getPromptNumber(), promptType, - new IpnbHtmlPanel((IpnbHtmlOutputCell)outputCell, myParent.getIpnbFilePanel(), ipnbCodePanel)); + new IpnbHtmlPanel((IpnbHtmlOutputCell)outputCell, myParent.getIpnbFilePanel(), this)); } else if (outputCell instanceof IpnbLatexOutputCell) { addPromptPanel(panel, myCell.getPromptNumber(), promptType, - new IpnbLatexPanel((IpnbLatexOutputCell)outputCell, myParent.getIpnbFilePanel(), ipnbCodePanel)); + new IpnbLatexPanel((IpnbLatexOutputCell)outputCell, myParent.getIpnbFilePanel(), this)); } else if (outputCell instanceof IpnbErrorOutputCell) { addPromptPanel(panel, myCell.getPromptNumber(), promptType, - new IpnbErrorPanel((IpnbErrorOutputCell)outputCell, ipnbCodePanel)); + new IpnbErrorPanel((IpnbErrorOutputCell)outputCell, this)); } else if (outputCell instanceof IpnbStreamOutputCell) { addPromptPanel(panel, myCell.getPromptNumber(), IpnbEditorUtil.PromptType.None, - new IpnbStreamPanel((IpnbStreamOutputCell)outputCell, ipnbCodePanel)); + new IpnbStreamPanel((IpnbStreamOutputCell)outputCell, this)); } else if (outputCell.getSourceAsString() != null) { addPromptPanel(panel, myCell.getPromptNumber(), promptType, - new IpnbCodeOutputPanel<>(outputCell, myParent.getIpnbFilePanel(), ipnbCodePanel)); + new IpnbCodeOutputPanel<>(outputCell, myParent.getIpnbFilePanel(), this)); } mainPanel.add(panel); } @@ -253,8 +252,7 @@ public class IpnbCodePanel extends IpnbEditablePanel { public void runCell(boolean selectNext) { mySelectNext = selectNext; updateCellSource(); - isRunning = true; - updatePanel(null, null); + updatePrompt(); final IpnbConnectionManager connectionManager = IpnbConnectionManager.getInstance(myProject); connectionManager.executeCell(this); setEditing(false); @@ -272,32 +270,48 @@ public class IpnbCodePanel extends IpnbEditablePanel { myCell.setSource(Arrays.asList(StringUtil.splitByLinesKeepSeparators(text))); } - public void updatePanel(@Nullable final String replacementContent, @Nullable final List outputContent) { + public void updatePrompt() { + final Application application = ApplicationManager.getApplication(); + application.invokeAndWait(() -> { + myCell.setPromptNumber(-1); + myCell.removeCellOutputs(); + myViewPanel.removeAll(); + + final JComponent panel = createViewPanel(); + myViewPanel.add(panel); + }, ModalityState.stateForComponent(this)); + } + + public void finishExecution() { + final Application application = ApplicationManager.getApplication(); + application.invokeAndWait(() -> { + final String promptText = IpnbEditorUtil.prompt(myCell.getPromptNumber(), IpnbEditorUtil.PromptType.In); + myPromptLabel.setText(promptText); + final IpnbFilePanel filePanel = myParent.getIpnbFilePanel(); + setEditing(false); + filePanel.revalidateAndRepaint(); + if (mySelectNext) { + filePanel.selectNext(this, true); + } + }, ModalityState.stateForComponent(this)); + } + + public void updatePanel(@Nullable final String replacementContent, @Nullable final IpnbOutputCell outputContent) { final Application application = ApplicationManager.getApplication(); application.invokeAndWait(() -> { if (replacementContent != null) { myCell.setSource(Arrays.asList(StringUtil.splitByLinesKeepSeparators(replacementContent))); + String prompt = IpnbEditorUtil.prompt(null, IpnbEditorUtil.PromptType.In); + myCell.setPromptNumber(null); + myPromptLabel.setText(prompt); application.runWriteAction(() -> myCodeSourcePanel.getEditor().getDocument().setText(replacementContent)); } - myCell.removeCellOutputs(); - myViewPanel.removeAll(); - - isRunning = false; if (outputContent != null) { - for (IpnbOutputCell output : outputContent) { - myCell.addCellOutput(output); - } + myCell.addCellOutput(outputContent); + addOutputPanel(myViewPanel, outputContent, outputContent instanceof IpnbOutOutputCell); } - - final JComponent panel = createViewPanel(); - myViewPanel.add(panel); - final IpnbFilePanel filePanel = myParent.getIpnbFilePanel(); - setEditing(false); filePanel.revalidateAndRepaint(); - if (mySelectNext && (replacementContent != null || outputContent != null)) { - filePanel.selectNext(this, true); - } }, ModalityState.stateForComponent(this)); } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnection.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnection.java index 7e503a742142..1bd3803e1ab4 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnection.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnection.java @@ -15,21 +15,23 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.*; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; /** * @author vlan - *

- * To be removed - */ + * + * To be removed +*/ public class IpnbConnection { protected static final String API_URL = "/api"; protected static final String KERNELS_URL = API_URL + "/kernels"; protected static final String HTTP_POST = "POST"; // TODO: Serialize cookies for the authentication message - protected static final String authMessage = - "{\"header\":{\"msg_id\":\"\", \"msg_type\":\"connect_request\"}, \"parent_header\":\"\", \"metadata\":{}," + - "\"channel\":\"shell\" }"; + protected static final String authMessage = "{\"header\":{\"msg_id\":\"\", \"msg_type\":\"connect_request\"}, \"parent_header\":\"\", \"metadata\":{}," + + "\"channel\":\"shell\" }"; public static final String HTTP_DELETE = "DELETE"; @NotNull protected final URI myURI; @@ -45,7 +47,7 @@ public class IpnbConnection { private volatile boolean myIsIOPubOpen = false; protected volatile boolean myIsOpened = false; - private final ArrayList myOutput = new ArrayList<>(); + private IpnbOutputCell myOutput; private int myExecCount; @@ -284,43 +286,43 @@ public class IpnbConnection { } } - protected static void addCellOutput(@NotNull final PyContent content, ArrayList output) { + protected void addCellOutput(@NotNull final PyContent content) { if (content instanceof PyErrContent) { - output.add(new IpnbErrorOutputCell(((PyErrContent)content).getEvalue(), - ((PyErrContent)content).getEname(), ((PyErrContent)content).getTraceback(), null, null)); + myOutput = new IpnbErrorOutputCell(((PyErrContent)content).getEvalue(), + ((PyErrContent)content).getEname(), ((PyErrContent)content).getTraceback(), null, null); } else if (content instanceof PyStreamContent) { final String data = ((PyStreamContent)content).getData(); - output.add(new IpnbStreamOutputCell(((PyStreamContent)content).getName(), Lists.newArrayList(data), null, null)); + myOutput = new IpnbStreamOutputCell(((PyStreamContent)content).getName(), Lists.newArrayList(data), null, null); } else if (content instanceof PyOutContent) { final Map data = ((PyOutContent)content).getData(); final String plainText = (String)data.get("text/plain"); if (data.containsKey("text/latex")) { final String text = (String)data.get("text/latex"); - output.add(new IpnbLatexOutputCell(Lists.newArrayList(text), null, Lists.newArrayList(plainText), null)); + myOutput = new IpnbLatexOutputCell(Lists.newArrayList(text), null, Lists.newArrayList(plainText), null); } else if (data.containsKey("text/html")) { final String html = (String)data.get("text/html"); - output.add(new IpnbHtmlOutputCell(Lists.newArrayList(StringUtil.splitByLinesKeepSeparators(html)), + myOutput = new IpnbHtmlOutputCell(Lists.newArrayList(StringUtil.splitByLinesKeepSeparators(html)), Lists.newArrayList(StringUtil.splitByLinesKeepSeparators(html)), - ((PyOutContent)content).getExecutionCount(), null)); + ((PyOutContent)content).getExecutionCount(), null); } else if (data.containsKey("image/png")) { final String png = (String)data.get("image/png"); - output.add(new IpnbPngOutputCell(png, Lists.newArrayList(StringUtil.splitByLinesKeepSeparators(plainText)), null, null)); + myOutput = new IpnbPngOutputCell(png, Lists.newArrayList(StringUtil.splitByLinesKeepSeparators(plainText)), null, null); } else if (data.containsKey("image/jpeg")) { final String jpeg = (String)data.get("image/jpeg"); - output.add(new IpnbJpegOutputCell(jpeg, Lists.newArrayList(StringUtil.splitByLinesKeepSeparators(plainText)), null, null)); + myOutput = new IpnbJpegOutputCell(jpeg, Lists.newArrayList(StringUtil.splitByLinesKeepSeparators(plainText)), null, null); } else if (data.containsKey("image/svg")) { final String svg = (String)data.get("image/svg"); - output.add(new IpnbSvgOutputCell(Lists.newArrayList(StringUtil.splitByLinesKeepSeparators(svg)), - Lists.newArrayList(StringUtil.splitByLinesKeepSeparators(plainText)), null, null)); + myOutput = new IpnbSvgOutputCell(Lists.newArrayList(StringUtil.splitByLinesKeepSeparators(svg)), + Lists.newArrayList(StringUtil.splitByLinesKeepSeparators(plainText)), null, null); } else if (plainText != null) { - output.add(new IpnbOutOutputCell(Lists.newArrayList(plainText), ((PyOutContent)content).getExecutionCount(), null)); + myOutput = new IpnbOutOutputCell(Lists.newArrayList(plainText), ((PyOutContent)content).getExecutionCount(), null); } } } @@ -453,7 +455,8 @@ public class IpnbConnection { final String messageType = header.getMessageType(); if ("pyout".equals(messageType) || "display_data".equals(messageType) || "execute_result".equals(messageType)) { final PyOutContent content = gson.fromJson(msg.getContent(), PyOutContent.class); - addCellOutput(content, myOutput); + addCellOutput(content); + myListener.onOutput(IpnbConnection.this, parentHeader.getMessageId()); } if ("execute_reply".equals(messageType)) { final PyExecuteReplyContent content = gson.fromJson(msg.getContent(), PyExecuteReplyContent.class); @@ -464,14 +467,19 @@ public class IpnbConnection { myListener.onPayload(payload.text, parentHeader.getMessageId()); } } + if ("ok".equals(content.status) || "error".equals(content.status)) { + myListener.onFinished(IpnbConnection.this, parentHeader.getMessageId()); + } } else if ("pyerr".equals(messageType) || "error".equals(messageType)) { final PyErrContent content = gson.fromJson(msg.getContent(), PyErrContent.class); - addCellOutput(content, myOutput); + addCellOutput(content); + myListener.onOutput(IpnbConnection.this, parentHeader.getMessageId()); } else if ("stream".equals(messageType)) { final PyStreamContent content = gson.fromJson(msg.getContent(), PyStreamContent.class); - addCellOutput(content, myOutput); + addCellOutput(content); + myListener.onOutput(IpnbConnection.this, parentHeader.getMessageId()); } else if ("pyin".equals(messageType) || "execute_input".equals(messageType)) { final JsonElement executionCount = msg.getContent().get("execution_count"); @@ -479,14 +487,6 @@ public class IpnbConnection { myExecCount = executionCount.getAsInt(); } } - else if ("status".equals(messageType)) { - final PyStatusContent content = gson.fromJson(msg.getContent(), PyStatusContent.class); - final String executionState = content.getExecutionState(); - if ("idle".equals(executionState)) { - myListener.onOutput(IpnbConnection.this, parentHeader.getMessageId()); - myOutput.clear(); - } - } } @Override @@ -500,7 +500,7 @@ public class IpnbConnection { } } - public ArrayList getOutput() { + public IpnbOutputCell getOutput() { return myOutput; } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnectionListener.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnectionListener.java index 01c396db6cfd..360d93d708ef 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnectionListener.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnectionListener.java @@ -16,4 +16,7 @@ public interface IpnbConnectionListener { void onPayload(@Nullable final String payload, @NotNull String parentMessageId); + + void onFinished(@NotNull IpnbConnection connection, + @NotNull String parentMessageId); } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnectionListenerBase.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnectionListenerBase.java index 61a97a4b193d..cc35a76fe2ea 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnectionListenerBase.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/protocol/IpnbConnectionListenerBase.java @@ -19,4 +19,8 @@ public class IpnbConnectionListenerBase implements IpnbConnectionListener { public void onPayload(@Nullable final String payload, @NotNull String parentMessageId) { } + + @Override + public void onFinished(@NotNull IpnbConnection connection, @NotNull String parentMessageId) { + } } diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbUnresolvedReferenceSkipper.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbUnresolvedReferenceSkipper.java new file mode 100644 index 000000000000..24cbdfedbfe5 --- /dev/null +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/psi/IpnbUnresolvedReferenceSkipper.java @@ -0,0 +1,70 @@ +package org.jetbrains.plugins.ipnb.psi; + +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.*; +import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferenceSkipperExtPoint; +import com.jetbrains.python.psi.PyElement; +import com.jetbrains.python.psi.PyImportedNameDefiner; +import com.jetbrains.python.psi.PyRecursiveElementVisitor; +import com.jetbrains.python.psi.PyReferenceOwner; +import com.jetbrains.python.psi.resolve.ImportedResolveResult; +import com.jetbrains.python.psi.resolve.PyResolveContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.ipnb.editor.panels.IpnbEditablePanel; +import org.jetbrains.plugins.ipnb.editor.panels.IpnbFilePanel; +import org.jetbrains.plugins.ipnb.editor.panels.code.IpnbCodePanel; + +import java.util.List; + +public class IpnbUnresolvedReferenceSkipper implements PyUnresolvedReferenceSkipperExtPoint { + @Override + public boolean unusedImportShouldBeSkipped(@NotNull final PyImportedNameDefiner importNameDefiner) { + final PsiFile file = importNameDefiner.getContainingFile(); + if (file instanceof IpnbPyFragment) { + final IpnbFilePanel panel = ((IpnbPyFragment)file).getFilePanel(); + final List panels = panel.getIpnbPanels(); + + for (IpnbEditablePanel editablePanel : panels) { + if (!(editablePanel instanceof IpnbCodePanel)) continue; + final Editor editor = ((IpnbCodePanel)editablePanel).getEditor(); + final IpnbPyFragment psiFile = (IpnbPyFragment)PsiDocumentManager.getInstance(importNameDefiner.getProject()).getPsiFile(editor.getDocument()); + if (psiFile == null) continue; + final MyVisitor visitor = new MyVisitor(importNameDefiner); + psiFile.accept(visitor); + if (visitor.used) return true; + } + } + return false; + } + + private static class MyVisitor extends PyRecursiveElementVisitor { + private final PyImportedNameDefiner myImportNameDefiner; + boolean used = false; + + public MyVisitor(PyImportedNameDefiner importNameDefiner) { + myImportNameDefiner = importNameDefiner; + } + + @Override + public void visitPyElement(PyElement node) { + super.visitPyElement(node); + if (node instanceof PyReferenceOwner) { + final PyResolveContext resolveContext = PyResolveContext.noImplicits(); + final PsiPolyVariantReference reference = ((PyReferenceOwner)node).getReference(resolveContext); + PsiElement target = null; + final ResolveResult[] resolveResults = reference.multiResolve(false); + for (ResolveResult resolveResult : resolveResults) { + if (target == null && resolveResult.isValidResult()) { + target = resolveResult.getElement(); + } + if (resolveResult instanceof ImportedResolveResult) { + final PyImportedNameDefiner definer = ((ImportedResolveResult)resolveResult).getDefiner(); + if (myImportNameDefiner.equals(definer)) { + used = true; + } + } + } + } + } + } +} diff --git a/python/ipnb/testSrc/WebSocketConnectionTest.java b/python/ipnb/testSrc/WebSocketConnectionTest.java index 54fee6284591..698a3e146ac6 100644 --- a/python/ipnb/testSrc/WebSocketConnectionTest.java +++ b/python/ipnb/testSrc/WebSocketConnectionTest.java @@ -8,7 +8,6 @@ import org.jetbrains.plugins.ipnb.protocol.IpnbConnectionListenerBase; import java.io.IOException; import java.net.URISyntaxException; -import java.util.ArrayList; import java.util.List; /** @@ -52,10 +51,9 @@ public class WebSocketConnectionTest extends TestCase { public void onOutput(@NotNull IpnbConnection connection, @NotNull String parentMessageId) { if (myMessageId.equals(parentMessageId)) { - final ArrayList outputs = connection.getOutput(); - assertEquals(1, outputs.size()); - assertEquals(outputs.get(0).getClass(), IpnbOutOutputCell.class); - final List text = outputs.get(0).getText(); + final IpnbOutputCell output = connection.getOutput(); + assertEquals(output.getClass(), IpnbOutOutputCell.class); + final List text = output.getText(); assertNotNull(text); assertEquals("4", text.get(0)); evaluated.set(true); @@ -87,10 +85,9 @@ public class WebSocketConnectionTest extends TestCase { public void onOutput(@NotNull IpnbConnection connection, @NotNull String parentMessageId) { if (myMessageId.equals(parentMessageId)) { - final ArrayList outputs = connection.getOutput(); - assertEquals(1, outputs.size()); - assertEquals(outputs.get(0).getClass(), IpnbOutOutputCell.class); - final List text = outputs.get(0).getText(); + final IpnbOutputCell output = connection.getOutput(); + assertEquals(output.getClass(), IpnbOutOutputCell.class); + final List text = output.getText(); assertNotNull(text); assertEquals("7", text.get(0)); evaluated.set(true); diff --git a/python/src/com/jetbrains/python/psi/resolve/PythonSdkPathCache.java b/python/src/com/jetbrains/python/psi/resolve/PythonSdkPathCache.java index e95bf88da5ac..da6096f643e1 100644 --- a/python/src/com/jetbrains/python/psi/resolve/PythonSdkPathCache.java +++ b/python/src/com/jetbrains/python/psi/resolve/PythonSdkPathCache.java @@ -61,6 +61,18 @@ public class PythonSdkPathCache extends PythonPathCache implements Disposable { public PythonSdkPathCache(@NotNull final Project project, @NotNull final Sdk sdk) { myProject = project; mySdk = sdk; + if (project.isDisposed()) { + return; + } + Disposer.register(project, this); + project.getMessageBus().connect(this).subscribe(ProjectJdkTable.JDK_TABLE_TOPIC, new ProjectJdkTable.Adapter() { + @Override + public void jdkRemoved(Sdk jdk) { + if (jdk == sdk) { + Disposer.dispose(PythonSdkPathCache.this); + } + } + }); sdk.getRootProvider().addRootSetChangedListener(new RootProvider.RootSetChangedListener() { @Override public void rootSetChanged(RootProvider wrapper) { @@ -75,17 +87,6 @@ public class PythonSdkPathCache extends PythonPathCache implements Disposable { } }, this); VirtualFileManager.getInstance().addVirtualFileListener(new MyVirtualFileAdapter(), this); - if (!project.isDisposed()) { - project.getMessageBus().connect(this).subscribe(ProjectJdkTable.JDK_TABLE_TOPIC, new ProjectJdkTable.Adapter() { - @Override - public void jdkRemoved(Sdk jdk) { - if (jdk == sdk) { - Disposer.dispose(PythonSdkPathCache.this); - } - } - }); - Disposer.register(project, this); - } } @Override diff --git a/python/testData/MockSdk3.4/python_stubs/builtins.py b/python/testData/MockSdk3.4/python_stubs/builtins.py index 2d89595fbbfd..7d2a8470c747 100644 --- a/python/testData/MockSdk3.4/python_stubs/builtins.py +++ b/python/testData/MockSdk3.4/python_stubs/builtins.py @@ -678,9 +678,6 @@ class __coroutine(object): def __await__(self): return [] - def __iter__(self): - return [] - def close(self): pass diff --git a/spellchecker/src/com/intellij/spellchecker/ui/SpellCheckingEditorCustomization.java b/spellchecker/src/com/intellij/spellchecker/ui/SpellCheckingEditorCustomization.java index f2136095a6f0..500c933a5fc6 100644 --- a/spellchecker/src/com/intellij/spellchecker/ui/SpellCheckingEditorCustomization.java +++ b/spellchecker/src/com/intellij/spellchecker/ui/SpellCheckingEditorCustomization.java @@ -105,7 +105,7 @@ public class SpellCheckingEditorCustomization extends SimpleEditorCustomization return; } - Function strategy = file.getUserData(InspectionProfileWrapper.CUSTOMIZATION_KEY); + Function strategy = file.getUserData(InspectionProfileWrapper.CUSTOMIZATION_KEY); if (strategy == null) { file.putUserData(InspectionProfileWrapper.CUSTOMIZATION_KEY, strategy = new MyInspectionProfileStrategy()); } @@ -127,13 +127,13 @@ public class SpellCheckingEditorCustomization extends SimpleEditorCustomization } } - private static class MyInspectionProfileStrategy implements Function { + private static class MyInspectionProfileStrategy implements Function { private final Map myWrappers = new WeakHashMap<>(); private boolean myUseSpellCheck; @NotNull @Override - public InspectionProfileWrapper apply(@NotNull InspectionProfile inspectionProfile) { + public InspectionProfileWrapper apply(@NotNull InspectionProfileImpl inspectionProfile) { if (!READY) { return new InspectionProfileWrapper(inspectionProfile); }