Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2016-10-26 18:08:33 +02:00
82 changed files with 1435 additions and 1262 deletions
-1
View File
@@ -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
@@ -31,6 +31,7 @@ import javax.swing.AbstractAction
import javax.swing.Icon
import javax.swing.KeyStroke
class RecentTestsListPopup(popupStep: ListPopupStep<RecentTestsPopupEntry>,
private val testRunner: RecentTestRunner,
private val locator: TestLocator) : ListPopupImpl(popupStep) {
@@ -50,56 +51,13 @@ class RecentTestsListPopup(popupStep: ListPopupStep<RecentTestsPopupEntry>,
}
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<RecentTestsPopupEntry>,
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
}
@@ -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<PreContract> preContracts = new ContractInferenceInterpreter(method).inferContracts();
List<MethodContract> 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<PreContract> preContracts = methodNode == null || bodyNode == null ? Collections.emptyList() :
new ContractInferenceInterpreter(tree, TreeBackedLighterAST.wrap(methodNode), TreeBackedLighterAST.wrap(bodyNode)).inferContracts();
List<MethodContract> 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<MethodContract> postProcessContracts(PsiMethod myMethod, List<PreContract> rawContracts) {
List<MethodContract> contracts = ContainerUtil.concat(rawContracts, c -> c.toContracts(myMethod));
private static List<MethodContract> postProcessContracts(@NotNull PsiMethod method, @NotNull PsiCodeBlock body, List<PreContract> rawContracts) {
List<MethodContract> 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<MethodContract> 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<PreContract> 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<PreContract> 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<PreContract> result = handleDelegation(((PsiExpressionStatement)statements[0]).getExpression(), false);
if (result != null) return result;
}
}
return visitStatements(Collections.singletonList(myEmptyConstraints), statements);
}
@Nullable
private static List<PreContract> 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<PreContract> visitExpression(final List<ValueConstraint[]> 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<PreContract> 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<PreContract> 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<MethodContract> 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<PreContract> asPreContracts(List<MethodContract> 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<MethodContract> visitEqualityComparison(List<ValueConstraint[]> 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<MethodContract> 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<MethodContract> toContracts(List<ValueConstraint[]> states, ValueConstraint constraint) {
return ContainerUtil.map(states, state -> new MethodContract(state, constraint));
}
private List<MethodContract> visitLogicalOperation(PsiExpression[] operands, boolean conjunction, List<ValueConstraint[]> states) {
ValueConstraint breakValue = conjunction ? FALSE_VALUE : TRUE_VALUE;
List<MethodContract> finalStates = ContainerUtil.newArrayList();
for (PsiExpression operand : operands) {
List<PreContract> 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<MethodContract> knownContracts(List<PreContract> values) {
return ContainerUtil.mapNotNull(values, pc -> pc instanceof KnownContract ? ((KnownContract)pc).getContract() : null);
}
private static List<ValueConstraint[]> antecedentsReturning(List<PreContract> values, ValueConstraint result) {
return ContainerUtil.mapNotNull(knownContracts(values), contract -> contract.returnValue == result ? contract.arguments : null);
}
private static class CodeBlockContracts {
List<PreContract> accumulated = new ArrayList<>();
List<PsiDeclarationStatement> declarations = new ArrayList<>();
void addAll(List<PreContract> contracts) {
if (contracts.isEmpty()) return;
if (declarations.isEmpty()) {
accumulated.addAll(contracts);
} else {
accumulated.add(new SideEffectFilter(getVariableInitializers(), contracts));
}
}
@NotNull
List<PsiExpression> getVariableInitializers() {
return JBIterable.from(declarations).
flatMap(s -> JBIterable.of(s.getDeclaredElements())).
filter(PsiVariable.class).
flatMap(var -> JBIterable.of(var.getInitializer())).
toList();
}
}
@NotNull
private List<PreContract> visitStatements(List<ValueConstraint[]> 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<PreContract> conditionResults = visitExpression(states, ((PsiIfStatement)statement).getCondition());
PsiStatement thenBranch = ((PsiIfStatement)statement).getThenBranch();
if (thenBranch != null) {
result.addAll(visitStatements(antecedentsReturning(conditionResults, TRUE_VALUE), thenBranch));
}
List<ValueConstraint[]> 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<PreContract> 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;
}
}
@@ -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<LighterASTNode> getParameters() {
LighterASTNode paramList = firstChildOfType(myTree, myMethod, PARAMETER_LIST);
return paramList != null ? getChildrenOfType(myTree, paramList, PARAMETER) : Collections.emptyList();
}
List<PreContract> inferContracts() {
LighterASTNode[] statements = getStatements(myBody);
if (statements.length == 0) return Collections.emptyList();
if (statements.length == 1) {
if (statements[0].getTokenType() == RETURN_STATEMENT) {
List<PreContract> 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<PreContract> 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<PreContract> 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<PreContract> visitExpression(final List<ValueConstraint[]> 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<LighterASTNode> 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<LighterASTNode> children = getExpressionChildren(myTree, expr);
if (children.size() != 3) return Collections.emptyList();
List<PreContract> 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<MethodContract> 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<PreContract> asPreContracts(List<MethodContract> 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<MethodContract> visitEqualityComparison(List<ValueConstraint[]> 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<MethodContract> 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<MethodContract> toContracts(List<ValueConstraint[]> states, ValueConstraint constraint) {
return ContainerUtil.map(states, state -> new MethodContract(state, constraint));
}
private List<MethodContract> visitLogicalOperation(List<LighterASTNode> operands, boolean conjunction, List<ValueConstraint[]> states) {
ValueConstraint breakValue = conjunction ? FALSE_VALUE : TRUE_VALUE;
List<MethodContract> finalStates = ContainerUtil.newArrayList();
for (LighterASTNode operand : operands) {
List<PreContract> 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<MethodContract> knownContracts(List<PreContract> values) {
return ContainerUtil.mapNotNull(values, pc -> pc instanceof KnownContract ? ((KnownContract)pc).getContract() : null);
}
private static List<ValueConstraint[]> antecedentsReturning(List<PreContract> values, ValueConstraint result) {
return ContainerUtil.mapNotNull(knownContracts(values), contract -> contract.returnValue == result ? contract.arguments : null);
}
private static class CodeBlockContracts {
List<PreContract> accumulated = new ArrayList<>();
List<ExpressionRange> varInitializers = new ArrayList<>();
void addAll(List<PreContract> 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<PreContract> visitStatements(List<ValueConstraint[]> 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<PreContract> conditionResults = visitExpression(states, findExpressionChild(myTree, statement));
LighterASTNode[] thenElse = getStatements(statement);
if (thenElse.length > 0) {
result.addAll(visitStatements(antecedentsReturning(conditionResults, TRUE_VALUE), thenElse[0]));
}
List<ValueConstraint[]> 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<PreContract> 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<LighterASTNode> 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;
}
}
@@ -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++) {
@@ -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);
@@ -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<MethodContract> 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<MethodContract> 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<MethodContract> 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<MethodContract> 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<PsiExpression> myExpressionsToCheck;
private final List<PreContract> myContracts;
SideEffectFilter(List<PsiExpression> expressionsToCheck, List<PreContract> contracts) {
myExpressionsToCheck = expressionsToCheck;
myContracts = contracts;
}
@NotNull
@Override
List<MethodContract> 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<MethodContract> 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<ValueConstraint[]> myStates;
MethodCallContract(PsiMethodCallExpression call, List<ValueConstraint[]> states) {
myCall = call;
myStates = states;
}
@NotNull
@Override
List<MethodContract> toContracts(@NotNull PsiMethod method) {
PsiMethod target = myCall.resolveMethod();
if (target != null && NullableNotNullManager.isNotNull(target)) {
return ContractInferenceInterpreter.toContracts(myStates, NOT_NULL_VALUE);
}
return Collections.emptyList();
}
}
@@ -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);
});
@@ -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)
@@ -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<MethodContract>
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<MethodContract> {
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<PsiParameter>,
callArguments: Array<PsiExpression>,
varArgCall: Boolean,
targetContract: MethodContract): MethodContract? {
var answer: Array<MethodContract.ValueConstraint>? = 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<ExpressionRange>, private val contracts: List<PreContract>) : PreContract {
override fun toContracts(method: PsiMethod, body: PsiCodeBlock): List<MethodContract> {
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<Array<MethodContract.ValueConstraint>>) : PreContract {
override fun toContracts(method: PsiMethod, body: PsiCodeBlock): List<MethodContract> {
val target = (call.restoreExpression(body) as PsiMethodCallExpression?)?.resolveMethod()
if (target != null && NullableNotNullManager.isNotNull(target)) {
return ContractInferenceInterpreter.toContracts(states, NOT_NULL_VALUE)
}
return emptyList()
}
}
@@ -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 {
"</profile>", 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);
@@ -35,7 +35,6 @@ import java.util.List;
* Date: Dec 7, 2004
*/
public interface InspectionProfile extends Profile {
HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey inspectionToolKey, PsiElement element);
/**
@@ -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);
}
}
@@ -34,9 +34,4 @@ public interface Profile extends Comparable, Scheme {
@Override
@NotNull
String getName();
void setProfileManager(@NotNull ProfileManager profileManager);
@NotNull
ProfileManager getProfileManager();
}
@@ -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<Profile> 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();
}
@@ -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<Key, GlobalInspectionContextExtension> 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<RefManagerImpl>() {
@Override
public RefManagerImpl compute() {
return new RefManagerImpl(myProject, myCurrentScope, GlobalInspectionContextBase.this);
}
});
myRefManager = ApplicationManager.getApplication().runReadAction(
(Computable<RefManagerImpl>)() -> new RefManagerImpl(myProject, myCurrentScope, this));
}
return myRefManager;
}
@@ -326,7 +327,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
@NotNull
protected List<Tools> getUsedTools() {
InspectionProfileImpl profile = (InspectionProfileImpl)getCurrentProfile();
InspectionProfileImpl profile = getCurrentProfile();
List<Tools> tools = profile.getAllEnabledInspectionTools(myProject);
Set<InspectionToolWrapper> 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;
}
@@ -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)) {
@@ -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<? super InspectionProfileImpl> 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<? super InspectionProfileImpl> 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<? super InspectionProfileImpl> dataHolder) {
this(profileName, registrar, profileManager, getBaseProfile(), dataHolder);
}
@@ -138,7 +150,7 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel,
public List<InspectionToolWrapper> 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
@@ -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<Function<InspectionProfile, InspectionProfileWrapper>> CUSTOMIZATION_KEY = Key.create("Inspection Profile Wrapper Customization");
public static final Key<Function<InspectionProfileImpl, InspectionProfileWrapper>> 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;
}
}
@@ -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<String, List<String>> dependencies) throws InvalidDataException {
void readExternal(@NotNull Element toolElement, @NotNull InspectionProfileManager profileManager, Map<String, List<String>> 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<Element> scopeElements = toolElement.getChildren(ProfileEx.SCOPE);
final List<String> 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<String> 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<String> 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<String> 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));
}
}
}
@@ -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;
}
}
@@ -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)
}
}
@@ -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;
@@ -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<InspectionProfile> 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);
}
@@ -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<Profile> {
@Synchronized override fun getProfiles(): Collection<InspectionProfile> {
currentProfile
return schemeManager.allSchemes
}
@Synchronized override fun getAvailableProfileNames(): Array<String> = schemeManager.allSchemeNames.toTypedArray()
@Synchronized fun getAvailableProfileNames(): Array<String> = 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?
}
}
@@ -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;
@@ -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;
}
@@ -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()) {
@@ -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<WordOccurrence> 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; }
@@ -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<InspectionProfile, InspectionProfileWrapper> custom = file.getUserData(InspectionProfileWrapper.CUSTOMIZATION_KEY);
Function<InspectionProfileImpl, InspectionProfileWrapper> 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<InspectionContext> init = visitPriorityElementsAndInit(toolToSpecifiedLanguageIds, iManager, isOnTheFly, progress, inside, session, toolWrappers, elementDialectIds);
List<InspectionContext> 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<PsiElement> elements,
@NotNull final LocalInspectionToolSession session,
@NotNull List<LocalInspectionToolWrapper> wrappers,
@NotNull final Set<String> elementDialectIds) {
final List<InspectionContext> init = new ArrayList<>();
List<Map.Entry<LocalInspectionToolWrapper, Set<String>>> entries = new ArrayList<>(toolToSpecifiedLanguageIds.entrySet());
@@ -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<Profile> 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;
}
@@ -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) {
@@ -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);
}
@@ -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<String>() {
@Override
@Nullable
public String compute() {
return OfflineViewParseUtil.parseProfileName(LoadTextUtil.loadText(inspectionFile).toString());
}
}
(Computable<String>)() -> 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<String, Map<String, Set<OfflineProblemDescriptor>>> resMap,
@NotNull InspectionProfile inspectionProfile,
@NotNull InspectionProfileImpl inspectionProfile,
@NotNull String title) {
final AnalysisScope scope = new AnalysisScope(project);
final InspectionManagerEx managerEx = (InspectionManagerEx)InspectionManager.getInstance(project);
@@ -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<Profile> getProfiles() {
public Collection<InspectionProfile> 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()) {
@@ -108,7 +108,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren
private final ConcurrentMap<HighlightDisplayLevel, ConcurrentMap<String, InspectionGroupNode>> 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> 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 {
@@ -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<VirtualFile> processor = virtualFile -> {
Consumer<VirtualFile> 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<VirtualFile> virtualFiles, Consumer<VirtualFile> searchInFile) {
ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator();
List<Future<?>> 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<Future<?>> 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
@@ -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;
}
@@ -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
@@ -64,17 +64,15 @@ public class CustomRegionStructureUtil {
}
private static Collection<CustomRegionTreeElement> collectCustomRegions(@NotNull PsiElement rootElement, @NotNull Set<TextRange> ranges) {
Iterator<PsiComment> iterator = SyntaxTraverser.psiTraverser(rootElement)
.regard(element -> !isInsideRanges(element, ranges))
.filter(PsiComment.class)
.filter(comment -> !comment.textContains('\n'))
Iterator<PsiElement> iterator = SyntaxTraverser.psiTraverser(rootElement)
.regard(element -> isCustomRegionCommentCandidate(element) && !isInsideRanges(element, ranges))
.iterator();
List<CustomRegionTreeElement> 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<TextRange> 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');
}
}
@@ -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<HighlightSeverity> severities = ((InspectionProfileImpl)selectedProfile).getUsedSeverities();
private static void copyUsedSeveritiesIfUndefined(InspectionProfileImpl selectedProfile, BaseInspectionProfileManager profileManager) {
final SeverityRegistrar registrar = profileManager.getSeverityRegistrar();
final Set<HighlightSeverity> severities = selectedProfile.getUsedSeverities();
for (Iterator<HighlightSeverity> 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();
@@ -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<SingleInspectionProfilePanel> myPanels = new ArrayList<>();
private final List<Profile> myDeletedProfiles = new ArrayList<>();
private final List<InspectionProfileImpl> 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<Profile> getProfiles() {
@@ -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) {
@@ -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<Character, Integer> charToVKeyMap =
new HashMap<>();
private static final TObjectIntHashMap<Character> 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;
}
@@ -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<EventDispatcher> myDispatchers = new LinkedHashSet<>();
private final Set<EventDispatcher> myPostProcessors = new LinkedHashSet<>();
private final List<EventDispatcher> myDispatchers = ContainerUtil.createLockFreeCopyOnWriteList();
private final List<EventDispatcher> myPostProcessors = ContainerUtil.createLockFreeCopyOnWriteList();
private final Set<Runnable> 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<EventDispatcher> set) {
private static void _addProcessor(@NotNull EventDispatcher dispatcher, Disposable parent, @NotNull Collection<EventDispatcher> 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<AWTEvent> exitCondition) {
public void pumpEventsForHierarchy(Component modalComponent, @NotNull Condition<AWTEvent> 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 <code>blockMode</code> equal to <code>COMPLETE</code>.
* 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 <code>blockMode</code> is <code>COMPLETE</code>, blocks following related mouse events completely, when <code>blockMode</code> is
* <code>ACTIONS</code> 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 <ESC> (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--);
}
@@ -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 <code>true</code> if and only if the passed event is already dispatched by the
* <code>IdeMouseEventDispatcher</code> and there is no need for any other processing of the event.
* If the method returns <code>false</code> 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;
@@ -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
@@ -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}
@@ -370,7 +370,6 @@
<add-to-group group-id="ToolsMenu" anchor="first"/>
<action id="NewScratchFile" class="com.intellij.ide.scratch.ScratchFileActions$NewFileAction" />
<action id="IdeScriptingConsole" class="com.intellij.execution.console.RunIdeConsoleAction"/>
</group>
<action id="NewScratchBuffer" class="com.intellij.ide.scratch.ScratchFileActions$NewBufferAction"/>
@@ -385,6 +384,7 @@
<group id="NewGroup" popup="true">
<action id="NewFile" class="com.intellij.ide.actions.CreateFileAction"/>
<action id="NewScratchFile" class="com.intellij.ide.scratch.ScratchFileActions$NewFileAction" />
<action id="NewDir" class="com.intellij.ide.actions.CreateDirectoryOrPackageAction"/>
<separator/>
<action id="NewFromTemplate" class="com.intellij.ide.fileTemplates.actions.CreateFromTemplateGroup"/>
@@ -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);
@@ -135,9 +135,8 @@ import java.util.*;
public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsightTestFixture {
private static final Function<IntentionAction, String> INTENTION_NAME_FUN = intentionAction -> "\"" + intentionAction.getText() + "\"";
private static final String START_FOLD = "<fold\\stext=\'[^\']*\'(\\sexpand=\'[^\']*\')*>";
private static final String END_FOLD = "</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<Border> 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 ? "<fold text=\'" + border.getText() + "\'" +
(withCollapseStatus ? " expand=\'" +
border.isExpanded() +
"\'" : "") +
">" : 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<HighlightInfo> highlighting, @NotNull String tagName, boolean withColor) {
public static <T extends Segment> String getTagsFromSegments(@NotNull String text,
@NotNull Collection<T> segments,
@NotNull String tagName,
@Nullable Function<T, String> attrCalculator) {
final List<Border> 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("</" + FOLD + ">", "");
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("</" + RAINBOW + ">", ""));
Assert.assertEquals(text, getHighlightingDescription(ContainerUtil.filter(doHighlighting(),
info -> info.type == RainbowHighlighter.RAINBOW_ELEMENT), RAINBOW,
withColor));
List<HighlightInfo> 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<Border> {
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() {
@@ -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();
@@ -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);
}
}
@@ -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<T> 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<T> 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<T> 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(),
@@ -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();
@@ -50,7 +50,12 @@ public class VcsLogTabsProperties implements PersistentStateComponent<VcsLogTabs
@NotNull
@Override
public State getState() {
return myState.TAB_STATES.get(id);
State state = myState.TAB_STATES.get(id);
if (state == null) {
state = new VcsLogUiPropertiesImpl.State();
myState.TAB_STATES.put(id, state);
}
return state;
}
@Override
@@ -18,6 +18,7 @@ package com.intellij.vcs.log.ui.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.ui.ScrollingUtil;
import com.intellij.vcs.log.VcsLogDataKeys;
import com.intellij.vcs.log.VcsLogUi;
import com.intellij.vcs.log.ui.VcsLogUiImpl;
@@ -44,6 +45,9 @@ public class ShowCommitTooltipAction extends DumbAwareAction {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
VcsLogGraphTable table = ((VcsLogUiImpl)e.getRequiredData(VcsLogDataKeys.VCS_LOG_UI)).getTable();
table.showTooltip(table.getSelectedRow());
int row = table.getSelectedRow();
if (ScrollingUtil.isVisible(table, row)) {
table.showTooltip(row);
}
}
}
@@ -208,7 +208,7 @@ public class GraphTableController {
public void showTooltip(int row) {
TableColumn rootColumn = myTable.getColumnModel().getColumn(GraphTableModel.ROOT_COLUMN);
Point point = new Point(rootColumn.getWidth() + myCommitRenderer.getToolipXCoordinate(row),
Point point = new Point(rootColumn.getWidth() + myCommitRenderer.getTooltipXCoordinate(row),
row * myTable.getRowHeight() + myTable.getRowHeight() / 2);
showTooltip(row, GraphTableModel.COMMIT_COLUMN, point, true);
}
@@ -213,7 +213,7 @@ public class GraphCommitCellRenderer extends ColoredTableCellRenderer {
return null;
}
public int getToolipXCoordinate(int row) {
public int getTooltipXCoordinate(int row) {
GraphCommitCell cell = getAssertCommitCell(myGraphTable.getModel().getValueAt(row, GraphTableModel.COMMIT_COLUMN));
Collection<VcsRef> refs = cell.getRefsToThisCommit();
if (!refs.isEmpty()) {
@@ -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
@@ -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
@@ -286,7 +286,8 @@ public abstract class MvcFramework {
}
public PathsList getApplicationClassPath(Module module) {
final List<VirtualFile> classPath = OrderEnumerator.orderEntries(module).recursively().withoutSdk().getPathsList().getVirtualFiles();
final List<VirtualFile> classPath = ContainerUtil.newArrayList();
classPath.addAll(OrderEnumerator.orderEntries(module).recursively().withoutSdk().getPathsList().getVirtualFiles());
retainOnlyJarsAndDirectories(classPath);
@@ -190,9 +190,6 @@ class __coroutine(object):
def __await__(self):
return []
def __iter__(self):
return []
def close(self):
pass
@@ -2455,12 +2455,6 @@ class __coroutine(object):
"""
return []
def __iter__(self):
"""
:rtype: collections.Iterable[unknown]
"""
return []
def close(self):
"""
:rtype: None
@@ -19,6 +19,7 @@
<dialectsTokenSetContributor implementation="org.jetbrains.plugins.ipnb.psi.IpnbPyTokenSetContributor"/>
<visitorFilter language="IpnbPython" implementationClass="org.jetbrains.plugins.ipnb.IpnbVisitorFilter"/>
<pep8ProblemSuppressor implementation="org.jetbrains.plugins.ipnb.IpnbPep8ProblemSuppressor"/>
<unresolvedReferenceSkipper implementation="org.jetbrains.plugins.ipnb.psi.IpnbUnresolvedReferenceSkipper"/>
</extensions>
<actions>
<action class="org.jetbrains.plugins.ipnb.editor.actions.IpnbRunCellInplaceAction" id="IpnbRunCellInplaceAction"
@@ -8,7 +8,7 @@
<properties/>
<border type="none"/>
<children>
<grid id="6ed7f" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="6ed7f" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
@@ -44,6 +44,20 @@
<text value="Working directory:"/>
</properties>
</component>
<component id="97534" class="com.intellij.ui.components.JBTextField" binding="myArgumentsField">
<constraints>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
<component id="83e21" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Arguments:"/>
</properties>
</component>
</children>
</grid>
</children>
@@ -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
@@ -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<IpnbOutputCell>)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<String, String> 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);
@@ -14,6 +14,7 @@ public class IpnbSettings implements PersistentStateComponent<IpnbSettings> {
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<IpnbSettings> {
return myWorkingDirectory;
}
public String getArguments() {
return myArguments;
}
public void setArguments(String arguments) {
myArguments = arguments;
}
@Override
public IpnbSettings getState() {
return this;
@@ -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 + " [*]:";
}
@@ -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());
}
}
}
@@ -33,10 +33,10 @@ public abstract class IpnbEditablePanel<T extends JComponent, K extends IpnbEdit
protected JTextArea myEditablePanel;
public final static String EDITABLE_PANEL = "Editable panel";
public final static String VIEW_PANEL = "View panel";
protected boolean isRunning = false;
private OnePixelSplitter mySplitter;
private JPanel myViewPrompt;
private JPanel myEditablePrompt;
protected JLabel myPromptLabel;
public IpnbEditablePanel(@NotNull K cell) {
super(cell);
@@ -97,12 +97,11 @@ public abstract class IpnbEditablePanel<T extends JComponent, K extends IpnbEdit
c.weightx = 0;
c.anchor = GridBagConstraints.NORTHWEST;
Integer number = promptNumber;
if (isRunning) {
number = -1;
}
final JComponent promptComponent = IpnbEditorUtil.createPromptComponent(number, promptType);
JLabel promptComponent = IpnbEditorUtil.createPromptComponent(promptNumber, promptType);
if (promptType == IpnbEditorUtil.PromptType.In) {
myPromptLabel = promptComponent;
}
c.insets = JBUI.insets(2, 2, 2, 5);
parent.add(promptComponent, c);
@@ -79,6 +79,7 @@ public class IpnbFilePanel extends JPanel implements Scrollable, DataProvider, D
alarm.cancelAllRequests();
alarm.addRequest(new MySynchronizeRequest(), 10, ModalityState.stateForComponent(IpnbFilePanel.this));
}
mySynchronize = true;
}
};
myDocument = myParent.getDocument();
@@ -469,7 +470,6 @@ public class IpnbFilePanel extends JPanel implements Scrollable, DataProvider, D
private class MySynchronizeRequest implements Runnable {
public void run() {
mySynchronize = false;
final Project project = getProject();
if (project.isDisposed()) {
return;
@@ -116,18 +116,17 @@ public class IpnbCodePanel extends IpnbEditablePanel<JComponent, IpnbCodeCell> {
}
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<JComponent, IpnbCodeCell> {
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<JComponent, IpnbCodeCell> {
}
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<JComponent, IpnbCodeCell> {
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<JComponent, IpnbCodeCell> {
myCell.setSource(Arrays.asList(StringUtil.splitByLinesKeepSeparators(text)));
}
public void updatePanel(@Nullable final String replacementContent, @Nullable final List<IpnbOutputCell> 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));
}
@@ -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
* <p>
* 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<IpnbOutputCell> 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<IpnbOutputCell> 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<String, Object> 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<IpnbOutputCell> getOutput() {
public IpnbOutputCell getOutput() {
return myOutput;
}
@@ -16,4 +16,7 @@ public interface IpnbConnectionListener {
void onPayload(@Nullable final String payload,
@NotNull String parentMessageId);
void onFinished(@NotNull IpnbConnection connection,
@NotNull String parentMessageId);
}
@@ -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) {
}
}
@@ -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<IpnbEditablePanel> 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;
}
}
}
}
}
}
}
@@ -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<IpnbOutputCell> outputs = connection.getOutput();
assertEquals(1, outputs.size());
assertEquals(outputs.get(0).getClass(), IpnbOutOutputCell.class);
final List<String> text = outputs.get(0).getText();
final IpnbOutputCell output = connection.getOutput();
assertEquals(output.getClass(), IpnbOutOutputCell.class);
final List<String> 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<IpnbOutputCell> outputs = connection.getOutput();
assertEquals(1, outputs.size());
assertEquals(outputs.get(0).getClass(), IpnbOutOutputCell.class);
final List<String> text = outputs.get(0).getText();
final IpnbOutputCell output = connection.getOutput();
assertEquals(output.getClass(), IpnbOutOutputCell.class);
final List<String> text = output.getText();
assertNotNull(text);
assertEquals("7", text.get(0));
evaluated.set(true);
@@ -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
@@ -678,9 +678,6 @@ class __coroutine(object):
def __await__(self):
return []
def __iter__(self):
return []
def close(self):
pass
@@ -105,7 +105,7 @@ public class SpellCheckingEditorCustomization extends SimpleEditorCustomization
return;
}
Function<InspectionProfile, InspectionProfileWrapper> strategy = file.getUserData(InspectionProfileWrapper.CUSTOMIZATION_KEY);
Function<InspectionProfileImpl, InspectionProfileWrapper> 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<InspectionProfile, InspectionProfileWrapper> {
private static class MyInspectionProfileStrategy implements Function<InspectionProfileImpl, InspectionProfileWrapper> {
private final Map<InspectionProfile, MyInspectionProfileWrapper> 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);
}