mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -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
|
||||
}
|
||||
+25
-350
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+396
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -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++) {
|
||||
|
||||
+3
-1
@@ -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();
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -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);
|
||||
});
|
||||
|
||||
+1
-1
@@ -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();
|
||||
}
|
||||
+22
-21
@@ -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
-27
@@ -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)) {
|
||||
|
||||
+46
-12
@@ -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
|
||||
|
||||
+4
-5
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -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;
|
||||
|
||||
+25
-2
@@ -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);
|
||||
}
|
||||
+6
-7
@@ -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; }
|
||||
|
||||
+4
-7
@@ -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;
|
||||
}
|
||||
|
||||
+2
-3
@@ -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) {
|
||||
|
||||
+2
-5
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+2
-9
@@ -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);
|
||||
|
||||
+10
-15
@@ -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
|
||||
|
||||
+4
-1
@@ -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
|
||||
|
||||
+9
-6
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
+16
-15
@@ -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();
|
||||
|
||||
+10
-12
@@ -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--);
|
||||
}
|
||||
|
||||
+9
-8
@@ -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);
|
||||
|
||||
+39
-56
@@ -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
|
||||
|
||||
+5
-1
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
-2
@@ -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
|
||||
|
||||
+5
-3
@@ -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
|
||||
|
||||
+17
-4
@@ -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 + " [*]:";
|
||||
}
|
||||
|
||||
+2
-9
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user