Report language of current file for mouse invocations of intentions popup (IDEA-CR-46747)

GitOrigin-RevId: 65667ea92fac4bef9b9a3b620b2cae0585171b4b
This commit is contained in:
Dmitry Jemerov
2019-05-03 02:17:10 +03:00
committed by intellij-monorepo-bot
parent 846eeb2d37
commit bfa87abd68
191 changed files with 2161 additions and 2608 deletions
@@ -11,6 +11,7 @@ import com.intellij.openapi.util.Ref;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.elements.PackagingElementFactory;
import com.intellij.util.PathUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collections;
@@ -79,7 +80,7 @@ public abstract class ArtifactEditorTestCase extends PackagingElementsTestCase {
final Ref<Boolean> dialogShown = Ref.create(false);
final TestDialog oldDialog = Messages.setTestDialog(new TestDialog() {
@Override
public int show(String message) {
public int show(@NotNull String message) {
dialogShown.set(true);
return 0;
}
@@ -2,6 +2,7 @@
package com.intellij.debugger.actions;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.engine.evaluation.EvaluateException;
@@ -26,7 +27,10 @@ import com.intellij.psi.*;
import com.intellij.util.DocumentUtil;
import com.intellij.util.Range;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import com.sun.jdi.Location;
import com.sun.jdi.Method;
import com.sun.jdi.ReferenceType;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -338,42 +342,67 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
if (!targets.isEmpty()) {
StackFrameProxyImpl frameProxy = suspendContext != null ? suspendContext.getFrameProxy() : null;
if (frameProxy != null) {
// sanity check
try {
Location location = frameProxy.location();
MethodBytecodeUtil.visit(location.method(), location.codeIndex(), new MethodVisitor(Opcodes.API_VERSION) {
boolean myLineMatch = false;
@Override
public void visitLineNumber(int line, Label start) {
myLineMatch = lines.isWithin(line - 1);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (myLineMatch) {
Iterator<SmartStepTarget> iterator = targets.iterator();
while (iterator.hasNext()) {
SmartStepTarget e = iterator.next();
if (e instanceof MethodSmartStepTarget &&
DebuggerUtilsEx.methodMatches(((MethodSmartStepTarget)e).getMethod(),
owner.replace("/", "."), name, desc,
suspendContext.getDebugProcess())) {
iterator.remove();
MethodSmartStepTarget target = (MethodSmartStepTarget)e;
// fix ordinals
existingMethodCalls(targets, target.getMethod())
.forEach(t -> {
int ordinal = t.getOrdinal();
if (ordinal > target.getOrdinal()) {
t.setOrdinal(ordinal - 1);
}
});
break;
}
List<MethodSmartStepTarget> methodTargets =
StreamEx.of(targets)
.select(MethodSmartStepTarget.class)
.filter(target -> !target.needsBreakpointRequest())
.toList();
visitLinesMethods(frameProxy.location(), true, lines, (opcode, owner, name, desc, itf) -> {
if (name.startsWith("access$")) { // bridge method
ReferenceType cls = ContainerUtil.getFirstItem(frameProxy.getVirtualMachine().classesByName(owner));
if (cls != null) {
Method method = DebuggerUtils.findMethod(cls, name, desc);
if (method != null) {
MethodBytecodeUtil.visit(method, new MethodVisitor(Opcodes.API_VERSION) {
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if ("java/lang/AbstractMethodError".equals(owner)) {
return;
}
removeMatchingMethod(methodTargets, owner, name, desc, suspendContext.getDebugProcess());
}
}, false);
}
}
}
}, true);
else {
removeMatchingMethod(methodTargets, owner, name, desc, suspendContext.getDebugProcess());
}
});
if (!methodTargets.isEmpty()) {
return Collections.emptyList();
}
}
catch (Exception e) {
LOG.error(e);
}
// remove already executed
try {
visitLinesMethods(frameProxy.location(), false, lines, (opcode, owner, name, desc, itf) -> {
Iterator<SmartStepTarget> iterator = targets.iterator();
while (iterator.hasNext()) {
SmartStepTarget e = iterator.next();
if (e instanceof MethodSmartStepTarget &&
DebuggerUtilsEx.methodMatches(((MethodSmartStepTarget)e).getMethod(),
owner.replace("/", "."), name, desc,
suspendContext.getDebugProcess())) {
iterator.remove();
MethodSmartStepTarget target = (MethodSmartStepTarget)e;
// fix ordinals
existingMethodCalls(targets, target.getMethod())
.forEach(t -> {
int ordinal = t.getOrdinal();
if (ordinal > target.getOrdinal()) {
t.setOrdinal(ordinal - 1);
}
});
break;
}
}
});
}
catch (Exception e) {
LOG.info(e);
@@ -386,6 +415,42 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
return Collections.emptyList();
}
private static void removeMatchingMethod(List<MethodSmartStepTarget> targets,
String owner,
String name,
String desc,
DebugProcessImpl process) {
Iterator<MethodSmartStepTarget> iterator = targets.iterator();
while (iterator.hasNext()) {
if (DebuggerUtilsEx.methodMatches(iterator.next().getMethod(), owner.replace("/", "."), name, desc, process)) {
iterator.remove();
break;
}
}
}
private interface MethodInsnVisitor {
void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf);
}
private static void visitLinesMethods(Location location, boolean full, Range<Integer> lines, MethodInsnVisitor visitor) {
MethodBytecodeUtil.visit(location.method(), full ? Long.MAX_VALUE : location.codeIndex(), new MethodVisitor(Opcodes.API_VERSION) {
boolean myLineMatch = false;
@Override
public void visitLineNumber(int line, Label start) {
myLineMatch = lines.isWithin(line - 1);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (myLineMatch) {
visitor.visitMethodInsn(opcode, owner, name, desc, itf);
}
}
}, true);
}
private static StreamEx<MethodSmartStepTarget> existingMethodCalls(List<SmartStepTarget> targets, PsiMethod psiMethod) {
return StreamEx.of(targets)
.select(MethodSmartStepTarget.class)
@@ -38,7 +38,7 @@ public class TestFilesIndex extends MapReduceIndex<Integer, Void, UsedSources> {
@Nullable
Collection<Integer> getTestDataFor(int testId) throws IOException {
ForwardIndex forwardIndex = getForwardIndexMap();
KeyCollectionForwardIndexAccessor<Integer, Void> forwardIndexAccessor = (KeyCollectionForwardIndexAccessor<Integer, Void>)getForwardIndexAccessor();
KeyCollectionForwardIndexAccessor<Integer, Void, UsedSources> forwardIndexAccessor = (KeyCollectionForwardIndexAccessor<Integer, Void, UsedSources>)getForwardIndexAccessor();
return forwardIndexAccessor.deserializeData(forwardIndex.get(testId));
}
@@ -29,11 +29,11 @@ import com.intellij.ui.components.JBList;
import com.intellij.ui.popup.list.GroupedItemsListRenderer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.util.Collections;
@@ -55,7 +55,7 @@ public class ProjectTemplateList extends JPanel {
add(myPanel, BorderLayout.CENTER);
GroupedItemsListRenderer<ProjectTemplate> renderer = new GroupedItemsListRenderer<ProjectTemplate>(new ListItemDescriptorAdapter<ProjectTemplate>() {
@Nullable
@NotNull
@Override
public String getTextFor(ProjectTemplate value) {
return value.getName();
@@ -80,12 +80,7 @@ public class ProjectTemplateList extends JPanel {
}
};
myList.setCellRenderer(renderer);
myList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
updateSelection();
}
});
myList.getSelectionModel().addListSelectionListener(__ -> updateSelection());
Messages.installHyperlinkSupport(myDescriptionPane);
}
@@ -104,7 +99,7 @@ public class ProjectTemplateList extends JPanel {
}
}
public void setTemplates(List<ProjectTemplate> list, boolean preserveSelection) {
public void setTemplates(List<? extends ProjectTemplate> list, boolean preserveSelection) {
Collections.sort(list, (o1, o2) -> Comparing.compare(o1 instanceof ArchivedProjectTemplate, o2 instanceof ArchivedProjectTemplate));
int index = preserveSelection ? myList.getSelectedIndex() : -1;
@@ -142,13 +137,10 @@ public class ProjectTemplateList extends JPanel {
myList.setSelectedValue(template, true);
}
}
myList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
ProjectTemplate template = getSelectedTemplate();
if (template != null) {
PropertiesComponent.getInstance().setValue(PROJECT_WIZARD_TEMPLATE, template.getName());
}
myList.getSelectionModel().addListSelectionListener(__ -> {
ProjectTemplate template = getSelectedTemplate();
if (template != null) {
PropertiesComponent.getInstance().setValue(PROJECT_WIZARD_TEMPLATE, template.getName());
}
});
}
@@ -166,7 +158,7 @@ public class ProjectTemplateList extends JPanel {
}
@TestOnly
public boolean setSelectedTemplate(String name) {
boolean setSelectedTemplate(@NotNull String name) {
ListModel model1 = myList.getModel();
for (int j = 0; j < model1.getSize(); j++) {
if (name.equals(((ProjectTemplate)model1.getElementAt(j)).getName())) {
@@ -54,8 +54,6 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.net.URL;
import java.util.HashMap;
@@ -70,9 +68,9 @@ import java.util.*;
public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, Disposable {
private static final Logger LOG = Logger.getInstance(ProjectTypeStep.class);
public static final Convertor<FrameworkSupportInModuleProvider,String> PROVIDER_STRING_CONVERTOR =
private static final Convertor<FrameworkSupportInModuleProvider,String> PROVIDER_STRING_CONVERTOR =
o -> o.getId();
public static final Function<FrameworkSupportNode, String> NODE_STRING_FUNCTION = FrameworkSupportNodeBase::getId;
private static final Function<FrameworkSupportNode, String> NODE_STRING_FUNCTION = FrameworkSupportNodeBase::getId;
private static final String TEMPLATES_CARD = "templates card";
private static final String FRAMEWORKS_CARD = "frameworks card";
private static final String PROJECT_WIZARD_GROUP = "project.wizard.group";
@@ -106,12 +104,7 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
myProjectTypeList.setModel(new CollectionListModel<>(groups));
myProjectTypeList.setSelectionModel(new SingleSelectionModel());
myProjectTypeList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
updateSelection();
}
});
myProjectTypeList.addListSelectionListener(__ -> updateSelection());
myProjectTypeList.setCellRenderer(new GroupedItemsListRenderer<TemplatesGroup>(new ListItemDescriptorAdapter<TemplatesGroup>() {
@Nullable
@Override
@@ -187,19 +180,9 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
}
};
myProjectTypeList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
projectTypeChanged();
}
});
myProjectTypeList.getSelectionModel().addListSelectionListener(__ -> projectTypeChanged());
myTemplatesList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
updateSelection();
}
});
myTemplatesList.addListSelectionListener(__ -> updateSelection());
for (TemplatesGroup templatesGroup : myTemplatesMap.keySet()) {
ModuleBuilder builder = templatesGroup.getModuleBuilder();
@@ -239,7 +222,7 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
return ContainerUtil.intersects(Arrays.asList(roles), acceptable);
}
public static MultiMap<TemplatesGroup, ProjectTemplate> getTemplatesMap(WizardContext context) {
private static MultiMap<TemplatesGroup, ProjectTemplate> getTemplatesMap(WizardContext context) {
ProjectTemplatesFactory[] factories = ProjectTemplatesFactory.EP_NAME.getExtensions();
final MultiMap<TemplatesGroup, ProjectTemplate> groups = new MultiMap<>();
for (ProjectTemplatesFactory factory : factories) {
@@ -351,7 +334,7 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
}
// new TemplatesGroup selected
public void projectTypeChanged() {
private void projectTypeChanged() {
TemplatesGroup group = getSelectedGroup();
if (group == null || group == myLastSelectedGroup) return;
myLastSelectedGroup = group;
@@ -431,7 +414,7 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
showCard(TEMPLATES_CARD);
}
private void setTemplatesList(TemplatesGroup group, Collection<ProjectTemplate> templates, boolean preserveSelection) {
private void setTemplatesList(TemplatesGroup group, Collection<? extends ProjectTemplate> templates, boolean preserveSelection) {
List<ProjectTemplate> list = new ArrayList<>(templates);
ModuleBuilder moduleBuilder = group.getModuleBuilder();
if (moduleBuilder != null && !(moduleBuilder instanceof TemplateModuleBuilder)) {
@@ -463,7 +446,7 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
}
@Nullable
public ProjectTemplate getSelectedTemplate() {
private ProjectTemplate getSelectedTemplate() {
return myCurrentCard == TEMPLATES_CARD ? myTemplatesList.getSelectedTemplate() : null;
}
@@ -77,14 +77,12 @@ public class UIRootConfigurationAccessor extends RootConfigurationAccessor {
@Override
@Nullable
public String getProjectSdkName(final Project project) {
final String projectJdkName = ProjectRootManager.getInstance(project).getProjectSdkName();
final Sdk projectJdk = getProjectSdk(project);
if (projectJdk != null) {
return projectJdk.getName();
}
else {
final ProjectSdksModel projectJdksModel = ProjectStructureConfigurable.getInstance(project).getProjectJdksModel();
return projectJdksModel.findSdk(projectJdkName) == null ? projectJdkName : null;
}
final String projectJdkName = ProjectRootManager.getInstance(project).getProjectSdkName();
final ProjectSdksModel projectJdksModel = ProjectStructureConfigurable.getInstance(project).getProjectJdksModel();
return projectJdkName != null && projectJdksModel.findSdk(projectJdkName) == null ? projectJdkName : null;
}
}
@@ -17,6 +17,7 @@ import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.io.HttpRequests;
import org.intellij.lang.annotations.Language;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NotNull;
@@ -74,7 +75,7 @@ public class RemoteTemplatesFactory extends ProjectTemplatesFactory {
@NotNull
@TestOnly
public static MultiMap<String, ArchivedProjectTemplate> createFromText(@NotNull String value) throws IOException, JDOMException {
public static MultiMap<String, ArchivedProjectTemplate> createFromText(@NotNull @Language("XML") String value) throws IOException, JDOMException {
return create(JDOMUtil.load(value));
}
@@ -19,24 +19,25 @@ import com.intellij.util.containers.MultiMap;
*/
public class RemoteTemplatesTest extends NewProjectWizardTestCase {
public void testParsing() throws Exception {
MultiMap<String, ArchivedProjectTemplate> map = RemoteTemplatesFactory.createFromText("<templates>\n" +
" <template>\n" +
" <name>Facelets Demo</name>\n" +
" <description><![CDATA[\n" +
" Demonstrates IDEA support for Facelets technology\n" +
" ]]>\n" +
" </description>\n" +
" <path>facelets.zip</path>\n" +
" <moduleType>JAVA_MODULE</moduleType>\n" +
" </template>\n" +
" <template>\n" +
" <name>Incompatible</name>\n" +
" <description>Incompatible</description>\n" +
" <path>incompatible.zip</path>\n" +
" <moduleType>JAVA_MODULE</moduleType>\n" +
" <requiredPlugin>unknown.plugin</requiredPlugin>\n" +
" </template>\n" +
"</templates>");
MultiMap<String, ArchivedProjectTemplate> map = RemoteTemplatesFactory.createFromText(
"<templates>\n" +
" <template>\n" +
" <name>Facelets Demo</name>\n" +
" <description><![CDATA[\n" +
" Demonstrates IDEA support for Facelets technology\n" +
" ]]>\n" +
" </description>\n" +
" <path>facelets.zip</path>\n" +
" <moduleType>JAVA_MODULE</moduleType>\n" +
" </template>\n" +
" <template>\n" +
" <name>Incompatible</name>\n" +
" <description>Incompatible</description>\n" +
" <path>incompatible.zip</path>\n" +
" <moduleType>JAVA_MODULE</moduleType>\n" +
" <requiredPlugin>unknown.plugin</requiredPlugin>\n" +
" </template>\n" +
"</templates>");
assertEquals(1, map.size());
ProjectTemplate facelets = map.values().iterator().next();
@@ -65,7 +65,7 @@ public class AnnotateMethodFix implements LocalQuickFix {
@Override
public boolean startInWriteAction() {
return false;
return !annotateOverriddenMethods();
}
@Override
@@ -7,8 +7,11 @@ import com.intellij.codeInspection.dataFlow.instructions.Instruction;
import com.intellij.codeInspection.dataFlow.value.*;
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ObjectUtils;
import com.siyeh.ig.psiutils.ExpressionUtils;
import one.util.streamex.EntryStream;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.Contract;
@@ -244,6 +247,20 @@ public class TrackingDfaMemoryState extends DfaMemoryStateImpl {
return findChange(change -> change.getExpression() == expression, false);
}
@Contract("null -> null")
@Nullable
MemoryStateChange findSubExpressionPush(@Nullable PsiExpression expression) {
if (expression == null) return null;
PsiElement topElement = ExpressionUtils.getPassThroughParent(expression);
return findChange(change -> {
PsiExpression changeExpression = change.getExpression();
if (changeExpression == null) return false;
return changeExpression == expression ||
(PsiTreeUtil.isAncestor(expression, changeExpression, true) &&
ExpressionUtils.getPassThroughParent(changeExpression) == topElement);
}, false);
}
MemoryStateChange findRelation(DfaVariableValue value, @NotNull Predicate<Relation> relationPredicate, boolean startFromSelf) {
return findChange(change -> {
Change varChange = change.myChanges.get(value);
@@ -9,6 +9,7 @@ import com.intellij.codeInspection.dataFlow.instructions.*;
import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet;
import com.intellij.codeInspection.dataFlow.value.*;
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.Pair;
@@ -16,6 +17,8 @@ import com.intellij.openapi.util.Segment;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.ChildRole;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtil;
@@ -24,6 +27,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.BoolUtils;
import com.siyeh.ig.psiutils.ExpressionUtils;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -333,9 +337,10 @@ public class TrackingRunner extends StandardDataFlowRunner {
Warning caused by narrowing conversion
Warning caused by unary minus
Warning caused by final field initializer
TODO: 3. Check how it works with
Literal is not-null
TODO: 3. Check how it works with:
Inliners (notably: Stream API)
Ternary operators
Boxed numbers
TODO: 4. Check for possible performance disasters (likely on some code patterns current algo might blow up)
TODO: 5. Problem when interesting state doesn't reach the current condition, need to do something with this
*/
@@ -370,8 +375,8 @@ public class TrackingRunner extends StandardDataFlowRunner {
Instruction instruction = change.myInstruction;
if (instruction instanceof AssignInstruction && change.myTopOfStack == value) {
PsiExpression rValue = ((AssignInstruction)instruction).getRExpression();
CauseItem item = new CauseItem("'" + value + "' was assigned", rValue);
MemoryStateChange push = change.findExpressionPush(rValue);
CauseItem item = createAssignmentCause((AssignInstruction)instruction, value);
MemoryStateChange push = change.findSubExpressionPush(rValue);
if (push != null) {
item.addChildren(findConstantValueCause(rValue, push, expectedValue));
}
@@ -385,6 +390,29 @@ public class TrackingRunner extends StandardDataFlowRunner {
return new CauseItem[0];
}
@NotNull
@Contract("_, _ -> new")
private static CauseItem createAssignmentCause(AssignInstruction instruction, DfaValue target) {
PsiExpression rExpression = instruction.getRExpression();
PsiElement anchor = null;
if (rExpression != null) {
PsiElement parent = PsiUtil.skipParenthesizedExprUp(rExpression.getParent());
if (parent instanceof PsiAssignmentExpression) {
anchor = ((PsiAssignmentExpression)parent).getOperationSign();
}
else if (parent instanceof PsiVariable) {
ASTNode node = parent.getNode();
if (node instanceof CompositeElement) {
anchor = ((CompositeElement)node).findChildByRoleAsPsiElement(ChildRole.INITIALIZER_EQ);
}
}
if (anchor == null) {
anchor = rExpression;
}
}
return new CauseItem("'" + target + "' was assigned", anchor);
}
private static CauseItem[] findBooleanResultCauses(PsiExpression expression,
MemoryStateChange history,
boolean value) {
@@ -578,17 +606,17 @@ public class TrackingRunner extends StandardDataFlowRunner {
}
if (instruction instanceof AssignInstruction) {
DfaValue target = change.myTopOfStack;
PsiExpression rValue = PsiUtil.skipParenthesizedExprDown(((AssignInstruction)instruction).getRExpression());
PsiExpression rValue = ((AssignInstruction)instruction).getRExpression();
CauseItem item = createAssignmentCause((AssignInstruction)instruction, target);
if (target == value) {
CauseItem item = new CauseItem("'" + target + "' was assigned", rValue);
MemoryStateChange rValuePush = change.findExpressionPush(rValue);
MemoryStateChange rValuePush = change.findSubExpressionPush(rValue);
if (rValuePush != null) {
item.addChildren(findRelationCause(relation.myRelationType, rValuePush, counterPartChange));
}
return item;
}
if (target == relation.myCounterpart) {
return new CauseItem("'" + target + "' was assigned", rValue);
return item;
}
}
PsiExpression expression = change.getExpression();
@@ -617,14 +645,11 @@ public class TrackingRunner extends StandardDataFlowRunner {
if (factDef != null && expression != null) {
DfaValue value = factUse.myTopOfStack;
if (factDef.myInstruction instanceof AssignInstruction && factDef.myTopOfStack == value) {
PsiExpression rExpression = PsiUtil.skipParenthesizedExprDown(((AssignInstruction)factDef.myInstruction).getRExpression());
while (rExpression instanceof PsiTypeCastExpression) {
rExpression = PsiUtil.skipParenthesizedExprDown(((PsiTypeCastExpression)rExpression).getOperand());
}
PsiExpression rExpression = ((AssignInstruction)factDef.myInstruction).getRExpression();
if (rExpression != null) {
MemoryStateChange rValuePush = factDef.findExpressionPush(rExpression);
MemoryStateChange rValuePush = factDef.findSubExpressionPush(rExpression);
if (rValuePush != null) {
CauseItem assignmentItem = new CauseItem("'" + value + "' was assigned", rExpression);
CauseItem assignmentItem = createAssignmentCause((AssignInstruction)factDef.myInstruction, value);
Pair<MemoryStateChange, DfaNullability> rValueFact = rValuePush.findFact(rValuePush.myTopOfStack, DfaFactType.NULLABILITY);
assignmentItem.addChildren(findNullabilityCause(rValuePush, rValueFact.first, nullability));
return assignmentItem;
@@ -636,6 +661,12 @@ public class TrackingRunner extends StandardDataFlowRunner {
return new CauseItem("'" + expression.getText() + "' is known to be '" + nullability.getPresentationName() + "' from #ref", defExpression);
}
}
if (expression instanceof PsiTypeCastExpression) {
MemoryStateChange operandPush = factUse.findSubExpressionPush(((PsiTypeCastExpression)expression).getOperand());
if (operandPush != null) {
return findNullabilityCause(operandPush, factDef, nullability);
}
}
if (expression instanceof PsiMethodCallExpression) {
PsiMethodCallExpression call = (PsiMethodCallExpression)expression;
PsiMethod method = call.resolveMethod();
@@ -791,11 +822,11 @@ public class TrackingRunner extends StandardDataFlowRunner {
CauseItem item = new CauseItem(String.format(template, rangeText), factUse);
if (factDef != null) {
if (factDef.myInstruction instanceof AssignInstruction && factDef.myTopOfStack == value) {
PsiExpression rExpression = PsiUtil.skipParenthesizedExprDown(((AssignInstruction)factDef.myInstruction).getRExpression());
PsiExpression rExpression = ((AssignInstruction)factDef.myInstruction).getRExpression();
if (rExpression != null) {
MemoryStateChange rValuePush = factDef.findExpressionPush(rExpression);
MemoryStateChange rValuePush = factDef.findSubExpressionPush(rExpression);
if (rValuePush != null) {
CauseItem assignmentItem = new CauseItem("'" + value + "' was assigned", rExpression);
CauseItem assignmentItem = createAssignmentCause((AssignInstruction)factDef.myInstruction, value);
Pair<MemoryStateChange, LongRangeSet> rValueFact = rValuePush.findFact(rValuePush.myTopOfStack, DfaFactType.RANGE);
assignmentItem.addChildren(findRangeCause(rValuePush, rValueFact.first, range, "Value is %s"));
item.addChildren(assignmentItem);
@@ -550,21 +550,19 @@ public class RefJavaManagerImpl extends RefJavaManager {
//TODO support suppressions by comment tag in kotlin
private void processComments(@NotNull UElement node) {
for (UComment comment : node.getComments()) {
if (comment instanceof UComment) {
PsiElement psi = comment.getSourcePsi();
if (psi instanceof PsiDocComment) {
final PsiDocTag[] tags = ((PsiDocComment)psi).getTags();
for (PsiDocTag tag : tags) {
if (Comparing.strEqual(tag.getName(), SuppressionUtilCore.SUPPRESS_INSPECTIONS_TAG_NAME)) {
final PsiElement[] dataElements = tag.getDataElements();
if (dataElements.length > 0) {
final PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(psi, PsiModifierListOwner.class);
if (listOwner != null) {
final WritableRefElement element = (WritableRefElement)myRefManager.getReference(listOwner);
if (element != null) {
String suppression = StringUtil.join(dataElements, PsiElement::getText, ",");
element.addSuppression(suppression);
}
PsiElement psi = comment.getSourcePsi();
if (psi instanceof PsiDocComment) {
final PsiDocTag[] tags = ((PsiDocComment)psi).getTags();
for (PsiDocTag tag : tags) {
if (Comparing.strEqual(tag.getName(), SuppressionUtilCore.SUPPRESS_INSPECTIONS_TAG_NAME)) {
final PsiElement[] dataElements = tag.getDataElements();
if (dataElements.length > 0) {
final PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(psi, PsiModifierListOwner.class);
if (listOwner != null) {
final WritableRefElement element = (WritableRefElement)myRefManager.getReference(listOwner);
if (element != null) {
String suppression = StringUtil.join(dataElements, PsiElement::getText, ",");
element.addSuppression(suppression);
}
}
}
@@ -240,8 +240,10 @@ public class NullableNotNullManagerImpl extends NullableNotNullManager implement
if (container instanceof PsiPackage) {
PsiFile file = annotation.getContainingFile();
ProjectFileIndex index = ProjectRootManager.getInstance(file.getProject()).getFileIndex();
VirtualFile annotationRoot = index.getClassRootForFile(file.getVirtualFile());
VirtualFile ownerRoot = index.getClassRootForFile(owner.getContainingFile().getVirtualFile());
VirtualFile annotationFile = file.getVirtualFile();
VirtualFile annotationRoot = annotationFile == null ? null : index.getClassRootForFile(annotationFile);
VirtualFile ownerFile = owner.getContainingFile().getVirtualFile();
VirtualFile ownerRoot = ownerFile == null ? null : index.getClassRootForFile(ownerFile);
if (ownerRoot != null && !ownerRoot.equals(annotationRoot)) {
continue;
}
@@ -147,7 +147,7 @@ public class FindDfaProblemCauseFix implements LocalQuickFix, LowPriorityAction
highlighter.getAndSet(null).dropHighlight();
}
})
.setItemChosenCallback(cause -> ReadAction.run(() -> navigate(editor, file, cause.myCauseItem)))
.setItemChosenCallback(cause -> navigate(editor, file, cause.myCauseItem))
.createPopup();
popup.showInBestPositionFor(editor);
}
@@ -20,7 +20,6 @@ import com.intellij.lang.java.JavaLanguage;
import com.intellij.navigation.ChooseByNameContributorEx;
import com.intellij.navigation.GotoClassContributor;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiFile;
@@ -30,41 +29,15 @@ import com.intellij.psi.presentation.java.SymbolPresentationUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.util.ClassUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.Processors;
import com.intellij.util.indexing.FindSymbolParameters;
import com.intellij.util.indexing.IdFilter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
public class DefaultClassNavigationContributor implements ChooseByNameContributorEx, GotoClassContributor {
@Override
@NotNull
public String[] getNames(Project project, boolean includeNonProjectItems) {
GlobalSearchScope scope = includeNonProjectItems ? GlobalSearchScope.allScope(project) : GlobalSearchScope.projectScope(project);
List<String> result = new ArrayList<>();
Processor<String> processor = Processors.cancelableCollectProcessor(result);
processNames(processor, scope, IdFilter.getProjectIdFilter(project, includeNonProjectItems));
return ArrayUtil.toStringArray(result);
}
@Override
@NotNull
public NavigationItem[] getItemsByName(String name, final String pattern, Project project, boolean includeNonProjectItems) {
List<NavigationItem> result = new ArrayList<>();
Processor<NavigationItem> processor = Processors.cancelableCollectProcessor(result);
processElementsWithName(name, processor, FindSymbolParameters.wrap(pattern, project, includeNonProjectItems));
return result.isEmpty() ? NavigationItem.EMPTY_NAVIGATION_ITEM_ARRAY :
result.toArray(NavigationItem.EMPTY_NAVIGATION_ITEM_ARRAY);
}
@Override
public String getQualifiedName(final NavigationItem item) {
@@ -30,51 +30,13 @@ import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
public class DefaultSymbolNavigationContributor implements ChooseByNameContributorEx, GotoClassContributor {
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.DefaultSymbolNavigationContributor");
@Override
@NotNull
public String[] getNames(Project project, boolean includeNonProjectItems) {
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
Set<String> set = new HashSet<>();
Collections.addAll(set, cache.getAllMethodNames());
Collections.addAll(set, cache.getAllFieldNames());
Collections.addAll(set, cache.getAllClassNames());
return ArrayUtil.toStringArray(set);
}
@Override
@NotNull
public NavigationItem[] getItemsByName(String name, final String pattern, Project project, boolean includeNonProjectItems) {
GlobalSearchScope scope = includeNonProjectItems ? GlobalSearchScope.allScope(project) : GlobalSearchScope.projectScope(project);
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
Condition<PsiMember> qualifiedMatcher = getQualifiedNameMatcher(pattern);
List<PsiMember> result = new ArrayList<>();
for (PsiMethod method : cache.getMethodsByName(name, scope)) {
if (!method.isConstructor() && isOpenable(method) && !hasSuperMethod(method, scope, qualifiedMatcher, pattern)) {
result.add(method);
}
}
for (PsiField field : cache.getFieldsByName(name, scope)) {
if (isOpenable(field)) {
result.add(field);
}
}
for (PsiClass aClass : cache.getClassesByName(name, scope)) {
if (isOpenable(aClass)) {
result.add(aClass);
}
}
PsiMember[] array = result.toArray(PsiMember.EMPTY_ARRAY);
Arrays.sort(array, MyComparator.INSTANCE);
return array;
}
@Nullable
@Override
public String getQualifiedName(NavigationItem item) {
@@ -29,7 +29,5 @@ internal class RangeExpression(
override fun calculateQuickResult(context: ExpressionContext): Result? = calculateResult(context)
override fun requiresCommittedPSI(): Boolean = false
override fun calculateLookupItems(context: ExpressionContext): Array<out LookupElement> = LookupElement.EMPTY_ARRAY
}
@@ -2,7 +2,7 @@
Value is always false (x > 6 && y > 10)
Operand #1 of &&-chain is false (x > 6)
Left operand is 5 (x)
'x' was assigned (5)
'x' was assigned (=)
*/
class Test {
@@ -0,0 +1,19 @@
/*
Value is always false (foo == null)
'foo' was assigned (=)
One of the following happens:
Expression cannot be null as it's newly created object (new String("foo"))
or expression cannot be null as it's newly created object (new String("bar"))
*/
import org.jetbrains.annotations.Nullable;
class Test {
void test(boolean b) {
String foo = b ? new String("foo") : new String("bar");
if (<selection>foo == null</selection>) {
}
}
}
@@ -0,0 +1,20 @@
/*
Value is always false (foo > 3)
One of the following happens:
Left operand is 1 (foo)
'foo' was assigned (=)
or left operand is 2 (foo)
'foo' was assigned (=)
*/
import org.jetbrains.annotations.Nullable;
class Test {
void test(boolean b) {
int foo = b ? 1 : 2;
if (<selection>foo > 3</selection>) {
}
}
}
@@ -1,6 +1,6 @@
/*
Value is always true (b)
'b' was assigned (true)
'b' was assigned (=)
*/
class Test {
@@ -1,6 +1,6 @@
/*
Value is always false (s == null)
's' was assigned (s1)
's' was assigned (=)
Condition 's1 != null' was checked before (s1 == null)
*/
class Test {
@@ -1,9 +1,9 @@
/*
Value is always false (b4)
'b4' was assigned (b3)
'b3' was assigned (b2)
'b2' was assigned (b1)
'b1' was assigned (b)
'b4' was assigned (=)
'b3' was assigned (=)
'b2' was assigned (=)
'b1' was assigned (=)
'b == false' was established from condition (b)
*/
import org.jetbrains.annotations.NotNull;
@@ -1,9 +1,9 @@
/*
Value is always false (x == null)
One of the following happens:
'x' was assigned (new Object())
'x' was assigned (=)
Expression cannot be null as it's newly created object (new Object())
or 'x' was assigned ("foo")
or 'x' was assigned (=)
Expression cannot be null as it's literal ("foo")
*/
@@ -1,10 +1,10 @@
/*
Value is always false (y == null)
'y' was assigned (x)
'y' was assigned (=)
One of the following happens:
'x' was assigned (new Object())
'x' was assigned (=)
Expression cannot be null as it's newly created object (new Object())
or 'x' was assigned ("foo")
or 'x' was assigned (=)
Expression cannot be null as it's literal ("foo")
*/
@@ -1,10 +1,10 @@
/*
Value is always true (j >= 0)
Left operand is >= 0 (j)
'j' was assigned (i + 1)
'j' was assigned (=)
Result of '+' is >= 0 (i + 1)
Left operand is in {-1..Integer.MAX_VALUE-1} (i)
'i' was assigned (s.indexOf(' '))
'i' was assigned (=)
Value is in {-1..Integer.MAX_VALUE-1} (s.indexOf(' '))
*/
@@ -1,6 +1,6 @@
/*
Value is always false (s1 == null)
's1' was assigned (s.trim())
's1' was assigned (=)
Method 'trim' is externally annotated as 'non-null' (trim)
*/
class Test {
@@ -1,6 +1,6 @@
/*
Value is always true ((s = new Object()) != null)
's' was assigned (new Object())
's' was assigned (=)
Expression cannot be null as it's newly created object (new Object())
*/
@@ -1,6 +1,6 @@
/*
Value is always true (s != null)
's' was assigned (new Object())
's' was assigned (=)
Expression cannot be null as it's newly created object (new Object())
*/
@@ -1,6 +1,6 @@
/*
Value is always true (null == s)
's' was assigned (null)
's' was assigned (=)
*/
import org.jetbrains.annotations.NotNull;
@@ -1,6 +1,6 @@
/*
May be null (s)
's' was assigned (loadString())
's' was assigned (=)
Method 'loadString' is annotated as 'nullable' (@Nullable)
*/
@@ -1,6 +1,6 @@
/*
May be null (foo)
'foo' was assigned (getFoo())
'foo' was assigned (=)
Method 'getFoo' is annotated as 'nullable' (@Nullable)
*/
@@ -1,6 +1,6 @@
/*
Value is always false (s == s1)
's1' was assigned (null)
's1' was assigned (=)
and condition 's != null' was checked before (null == s)
*/
class Test {
@@ -6,14 +6,14 @@ Value is always true (x || (a+b)+(c+d)==10)
Result of '+' is 10 ((a+b)+(c+d))
Result of '+' is 3 (a+b)
Left operand is 1 (a)
'a' was assigned (1)
'a' was assigned (=)
and right operand is 2 (b)
'b' was assigned (2)
'b' was assigned (=)
and result of '+' is 7 (c+d)
Left operand is 3 (c)
'c' was assigned (3)
'c' was assigned (=)
and right operand is 4 (d)
'd' was assigned (4)
'd' was assigned (=)
*/
class Test {
@@ -149,4 +149,6 @@ public class DataFlowInspectionTrackerTest extends LightCodeInsightFixtureTestCa
public void testNpeSimple() { doTest(); }
public void testNpeAnnotation() { doTest(); }
public void testNpeWithCast() { doTest(); }
public void testAssignTernaryNotNull() { doTest(); }
public void testAssignTernaryNumeric() { doTest(); }
}
@@ -287,7 +287,7 @@ public class EditorTypingAndNavigationUndoTest extends EditorUndoTestCase {
Ref<String> message = new Ref<>();
Messages.setTestDialog(new TestDialog() {
@Override
public int show(String m) {
public int show(@NotNull String m) {
message.set(m);
return Messages.YES;
}
@@ -78,7 +78,7 @@ public class GlobalUndoTest extends UndoTestCase implements TestDialog {
}
@Override
public int show(String message) {
public int show(@NotNull String message) {
myConfirmationWasRequested = true;
return 0;
}
@@ -127,18 +127,18 @@ public abstract class ProjectWizardTestCase<T extends AbstractProjectWizard> ext
return createModuleFromWizard(project);
}
protected Module createModuleFromWizard(@NotNull Project project) {
private Module createModuleFromWizard(@NotNull Project project) {
return new NewModuleAction().createModuleFromWizard(project, null, myWizard);
}
protected void runWizard(@NotNull String group,
@Nullable final String name,
@Nullable Project project,
@Nullable final Consumer<? super Step> adjuster) throws IOException {
private void runWizard(@NotNull String group,
@Nullable final String name,
@Nullable Project project,
@Nullable final Consumer<? super Step> adjuster) throws IOException {
createWizard(project);
ProjectTypeStep step = (ProjectTypeStep)myWizard.getCurrentStepObject();
if (!step.setSelectedTemplate(group, name)) {
throw new IllegalArgumentException(group + '/' + name + " template not found, available groups " + step.availableTemplateGroupsToString());
throw new IllegalArgumentException(group + '/' + name + " template not found. Available groups: " + step.availableTemplateGroupsToString());
}
runWizard(step1 -> {
@@ -151,7 +151,7 @@ public abstract class ProjectWizardTestCase<T extends AbstractProjectWizard> ext
});
}
protected void runWizard(@Nullable Consumer<? super Step> adjuster) {
private void runWizard(@Nullable Consumer<? super Step> adjuster) {
while (true) {
ModuleWizardStep currentStep = myWizard.getCurrentStepObject();
if (adjuster != null) {
@@ -236,7 +236,7 @@ public abstract class ProjectWizardTestCase<T extends AbstractProjectWizard> ext
return ContainerUtil.getFirstItem(ImportModuleAction.createFromWizard(project, myWizard));
}
private static <T> T computeInWriteSafeContext(Supplier<T> supplier) {
private static <T> T computeInWriteSafeContext(Supplier<? extends T> supplier) {
Ref<T> module = Ref.create();
ApplicationManager.getApplication().invokeLater(() -> module.set(supplier.get()));
UIUtil.dispatchAllInvocationEvents();
@@ -15,6 +15,7 @@
*/
package org.jetbrains.jps.model.library.sdk;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.JpsElement;
import org.jetbrains.jps.model.JpsElementReference;
import org.jetbrains.jps.model.library.JpsTypedLibrary;
@@ -23,5 +24,6 @@ import org.jetbrains.jps.model.library.JpsTypedLibrary;
* @author nik
*/
public interface JpsSdkReference<P extends JpsElement> extends JpsElementReference<JpsTypedLibrary<JpsSdk<P>>> {
@NotNull
String getSdkName();
}
@@ -30,6 +30,7 @@ public abstract class JpsNamedElementReferenceBase<S extends JpsNamedElement, T
extends JpsCompositeElementBase<Self> implements JpsElementReference<T> {
private static final JpsElementChildRole<JpsElementReference<? extends JpsCompositeElement>> PARENT_REFERENCE_ROLE = JpsElementChildRoleBase
.create("parent");
@NotNull
protected final String myElementName;
protected JpsNamedElementReferenceBase(@NotNull String elementName, @NotNull JpsElementReference<? extends JpsCompositeElement> parentReference) {
@@ -53,6 +53,7 @@ public class JpsWrappedJavaSdkReferenceImpl extends JpsCompositeElementBase<JpsW
return new JpsWrappedJavaSdkReferenceImpl(this);
}
@NotNull
@Override
public String getSdkName() {
JpsTypedLibrary<JpsSdk<JpsDummyElement>> sdk = resolve();
@@ -0,0 +1,51 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class NlsCapitalizationUtil {
public static boolean isCapitalizationSatisfied(String value, Nls.Capitalization capitalization) {
if (StringUtil.isEmpty(value) || capitalization == Nls.Capitalization.NotSpecified) {
return true;
}
value = value.replace("&", "");
return capitalization == Nls.Capitalization.Title
? StringUtil.wordsToBeginFromUpperCase(value).equals(value)
: checkSentenceCapitalization(value);
}
private static boolean checkSentenceCapitalization(@NotNull String value) {
List<String> words = StringUtil.split(value, " ");
if (words.size() == 0) return true;
if (Character.isLetter(words.get(0).charAt(0)) && !isCapitalizedWord(words.get(0))) return false;
if (words.size() == 1) return true;
int capitalized = 1;
for (int i = 1, size = words.size(); i < size; i++) {
String word = words.get(i);
if (isCapitalizedWord(word)) {
// check for abbreviations like SQL or I18n
if (word.length() == 1 || !Character.isLowerCase(word.charAt(1))) {
continue;
}
capitalized++;
}
}
return capitalized / words.size() < 0.2; // allow reasonable amount of capitalized words
}
private static boolean isCapitalizedWord(String word) {
return word.length() > 0 && Character.isLetter(word.charAt(0)) && Character.isUpperCase(word.charAt(0));
}
@NotNull
public static String fixValue(String string, Nls.Capitalization capitalization) {
return capitalization == Nls.Capitalization.Title
? StringUtil.wordsToBeginFromUpperCase(string)
: StringUtil.capitalize(StringUtil.wordsToBeginFromLowerCase(string));
}
}
@@ -0,0 +1,37 @@
/*
* Copyright 2000-2019 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;
import junit.framework.TestCase;
import org.jetbrains.annotations.Nls;
import static com.intellij.codeInspection.NlsCapitalizationUtil.isCapitalizationSatisfied;
public class NlsCapitalizationUtilTest extends TestCase {
public void testCapitalization() {
assertTrue(isCapitalizationSatisfied("Fix SQL issues", Nls.Capitalization.Sentence));
assertTrue(isCapitalizationSatisfied("Fix I18n issues", Nls.Capitalization.Sentence));
assertTrue(isCapitalizationSatisfied("Fix C issues", Nls.Capitalization.Sentence));
assertTrue(isCapitalizationSatisfied("@charset is invalid", Nls.Capitalization.Sentence));
assertTrue(isCapitalizationSatisfied("Add 'this' qualifier", Nls.Capitalization.Sentence));
assertTrue(isCapitalizationSatisfied("Add 'this' qualifier", Nls.Capitalization.Sentence));
assertTrue(isCapitalizationSatisfied("Please select the configuration file (usually named IntelliLang.xml) to import.",
Nls.Capitalization.Sentence));
assertFalse(isCapitalizationSatisfied("Foo Bar", Nls.Capitalization.Sentence));
assertTrue(isCapitalizationSatisfied("Foo", Nls.Capitalization.Sentence));
}
}
@@ -10,12 +10,12 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="intellij.platform.jps.model" />
<orderEntry type="module" module-name="intellij.platform.jps.model.impl" />
<orderEntry type="module" module-name="intellij.platform.jps.model.serialization" />
<orderEntry type="library" name="kotlin-stdlib-jdk8" level="project" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="library" scope="TEST" name="JUnit4" level="project" />
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="PROVIDED" />
<orderEntry type="library" name="http-client" level="project" />
<orderEntry type="library" scope="RUNTIME" name="commons-imaging" level="project" />
<orderEntry type="module" module-name="intellij.platform.projectModel.impl" />
</component>
</module>
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.ide
import com.intellij.ide.impl.ProjectUtil.focusProjectWindow
@@ -72,7 +72,7 @@ internal class OpenFileHttpService : RestService() {
val apiRequest: OpenFileRequest
if (request.method() === HttpMethod.POST) {
apiRequest = gson.value.fromJson(createJsonReader(request), OpenFileRequest::class.java)
apiRequest = gson.fromJson(createJsonReader(request), OpenFileRequest::class.java)
}
else {
apiRequest = OpenFileRequest()
@@ -82,7 +82,7 @@ internal class OpenFileHttpService : RestService() {
apiRequest.focused = getBooleanParameter("focused", urlDecoder, true)
}
val prefixLength = 1 + PREFIX.length + 1 + serviceName.length + 1
val prefixLength = 1 + PREFIX.length + 1 + getServiceName().length + 1
val path = urlDecoder.path()
if (path.length > prefixLength) {
val matcher = LINE_AND_COLUMN.matcher(path).region(prefixLength, path.length)
@@ -1,309 +0,0 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.ide;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.google.gson.stream.MalformedJsonException;
import com.intellij.ide.IdeBundle;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.ui.AppIcon;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.NettyKt;
import com.intellij.util.net.NetUtils;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.builtInWebServer.BuiltInWebServerKt;
import org.jetbrains.io.Responses;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static com.intellij.ide.impl.ProjectUtil.showYesNoDialog;
/**
* Document your service using <a href="http://apidocjs.com">apiDoc</a>. To extract big example from source code, consider to use *.coffee file near your source file.
* (or Python/Ruby, but coffee recommended because it's plugin is lightweight). See {@link AboutHttpService} for example.
*
* Don't create JsonReader/JsonWriter directly, use only provided {@link #createJsonReader}, {@link #createJsonWriter} methods (to ensure that you handle in/out according to REST API guidelines).
*
* @see <a href="http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api">Best Practices for Designing a Pragmatic RESTful API</a>.
*/
public abstract class RestService extends HttpRequestHandler {
protected static final Logger LOG = Logger.getInstance(RestService.class);
public static final String PREFIX = "api";
protected final NotNullLazyValue<Gson> gson = new NotNullLazyValue<Gson>() {
@NotNull
@Override
protected Gson compute() {
return new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
}
};
private final LoadingCache<InetAddress, AtomicInteger> abuseCounter =
CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build(CacheLoader.from((Supplier<AtomicInteger>)AtomicInteger::new));
private final Cache<String, Boolean> trustedOrigins =
CacheBuilder.newBuilder().maximumSize(1024).expireAfterWrite(1, TimeUnit.DAYS).build();
@Override
public final boolean isSupported(@NotNull FullHttpRequest request) {
if (!isMethodSupported(request.method())) {
return false;
}
String uri = request.uri();
if (isPrefixlessAllowed() && checkPrefix(uri, getServiceName())) {
return true;
}
String serviceName = getServiceName();
int minLength = 1 + PREFIX.length() + 1 + serviceName.length();
if (uri.length() >= minLength &&
uri.charAt(0) == '/' &&
uri.regionMatches(true, 1, PREFIX, 0, PREFIX.length()) &&
uri.regionMatches(true, 2 + PREFIX.length(), serviceName, 0, serviceName.length())) {
if (uri.length() == minLength) {
return true;
}
else {
char c = uri.charAt(minLength);
return c == '/' || c == '?';
}
}
return false;
}
/**
* Service url must be "/api/$serviceName", but to preserve backward compatibility, prefixless path could be also supported
*/
protected boolean isPrefixlessAllowed() {
return false;
}
/**
* Use human-readable name or UUID if it is an internal service.
*/
@NotNull
protected abstract String getServiceName();
protected boolean isMethodSupported(@NotNull HttpMethod method) {
return method == HttpMethod.GET;
}
@Override
public final boolean process(@NotNull QueryStringDecoder urlDecoder, @NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context) {
try {
AtomicInteger counter = abuseCounter.get(((InetSocketAddress)context.channel().remoteAddress()).getAddress());
if (counter.incrementAndGet() > Registry.intValue("ide.rest.api.requests.per.minute", 30)) {
Responses.send(Responses.orInSafeMode(HttpResponseStatus.TOO_MANY_REQUESTS, HttpResponseStatus.OK), context.channel(), request);
return true;
}
if (!isHostTrusted(request, urlDecoder)) {
Responses.send(Responses.orInSafeMode(HttpResponseStatus.FORBIDDEN, HttpResponseStatus.OK), context.channel(), request);
return true;
}
String error = execute(urlDecoder, request, context);
if (error != null) {
Responses.send(HttpResponseStatus.BAD_REQUEST, context.channel(), request, error);
}
}
catch (Throwable e) {
HttpResponseStatus status;
// JsonReader exception
//noinspection InstanceofCatchParameter
if (e instanceof MalformedJsonException || (e instanceof IllegalStateException && e.getMessage().startsWith("Expected a "))) {
LOG.warn(e);
status = HttpResponseStatus.BAD_REQUEST;
}
else {
LOG.error(e);
status = HttpResponseStatus.INTERNAL_SERVER_ERROR;
}
Responses.send(status, context.channel(), request, ExceptionUtil.getThrowableText(e));
}
return true;
}
@SuppressWarnings("deprecation")
protected boolean isHostTrusted(@NotNull FullHttpRequest request, @NotNull QueryStringDecoder urlDecoder) throws InterruptedException, InvocationTargetException {
return isHostTrusted(request);
}
/**
* @deprecated Use {@link #isHostTrusted(FullHttpRequest, QueryStringDecoder)}
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
// e.g. upsource trust to configured host
protected boolean isHostTrusted(@NotNull FullHttpRequest request) throws InterruptedException, InvocationTargetException {
if (BuiltInWebServerKt.isSignedRequest(request)) {
return true;
}
String referrer = NettyKt.getOrigin(request);
if (referrer == null) {
referrer = NettyKt.getReferrer(request);
}
String host;
try {
host = StringUtil.nullize(referrer == null ? null : new URI(referrer).getHost());
}
catch (URISyntaxException ignored) {
return false;
}
Ref<Boolean> isTrusted = Ref.create();
if (host != null) {
if (NetUtils.isLocalhost(host)) {
isTrusted.set(true);
}
else {
isTrusted.set(trustedOrigins.getIfPresent(host));
}
}
if (isTrusted.isNull()) {
SwingUtilities.invokeAndWait(() -> {
AppIcon.getInstance().requestAttention(null, true);
isTrusted.set(showYesNoDialog(
IdeBundle.message("warning.use.rest.api", getServiceName(), ObjectUtils.chooseNotNull(host, "unknown host")),
"title.use.rest.api"));
if (host != null) {
trustedOrigins.put(host, isTrusted.get());
}
});
}
return isTrusted.get();
}
protected static void activateLastFocusedFrame() {
IdeFrame frame = IdeFocusManager.getGlobalInstance().getLastFocusedFrame();
if (frame instanceof Window) {
((Window)frame).toFront();
}
}
/**
* Return error or send response using {@link #sendOk(FullHttpRequest, ChannelHandlerContext)}, {@link #send(BufferExposingByteArrayOutputStream, HttpRequest, ChannelHandlerContext)}
*/
@Nullable("error text or null if successful")
public abstract String execute(@NotNull QueryStringDecoder urlDecoder, @NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context) throws IOException;
@NotNull
protected static JsonReader createJsonReader(@NotNull FullHttpRequest request) {
JsonReader reader = new JsonReader(new InputStreamReader(new ByteBufInputStream(request.content()), StandardCharsets.UTF_8));
reader.setLenient(true);
return reader;
}
@NotNull
protected static JsonWriter createJsonWriter(@NotNull OutputStream out) {
JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
writer.setIndent(" ");
return writer;
}
@Nullable
protected static Project getLastFocusedOrOpenedProject() {
IdeFrame lastFocusedFrame = IdeFocusManager.getGlobalInstance().getLastFocusedFrame();
Project project = lastFocusedFrame == null ? null : lastFocusedFrame.getProject();
if (project == null) {
Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
return openProjects.length > 0 ? openProjects[0] : null;
}
return project;
}
protected static void sendOk(@NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context) {
sendStatus(HttpResponseStatus.OK, HttpUtil.isKeepAlive(request), context.channel());
}
protected static void sendStatus(@NotNull HttpResponseStatus status, boolean keepAlive, @NotNull Channel channel) {
DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status);
HttpUtil.setContentLength(response, 0);
Responses.addCommonHeaders(response);
Responses.addNoCache(response);
if (keepAlive) {
HttpUtil.setKeepAlive(response, true);
}
response.headers().set("X-Frame-Options", "Deny");
Responses.send(response, channel, !keepAlive);
}
protected static void send(@NotNull BufferExposingByteArrayOutputStream byteOut, @NotNull HttpRequest request, @NotNull ChannelHandlerContext context) {
HttpResponse response = Responses.response("application/json", Unpooled.wrappedBuffer(byteOut.getInternalBuffer(), 0, byteOut.size()));
sendResponse(request, context, response);
}
protected static void sendResponse(@NotNull HttpRequest request, @NotNull ChannelHandlerContext context, @NotNull HttpResponse response) {
Responses.addNoCache(response);
response.headers().set("X-Frame-Options", "Deny");
Responses.send(response, context.channel(), request);
}
@Nullable
protected static String getStringParameter(@NotNull String name, @NotNull QueryStringDecoder urlDecoder) {
return ContainerUtil.getLastItem(urlDecoder.parameters().get(name));
}
protected static int getIntParameter(@NotNull String name, @NotNull QueryStringDecoder urlDecoder) {
return StringUtilRt.parseInt(StringUtil.nullize(ContainerUtil.getLastItem(urlDecoder.parameters().get(name)), true), -1);
}
protected static boolean getBooleanParameter(@NotNull String name, @NotNull QueryStringDecoder urlDecoder) {
return getBooleanParameter(name, urlDecoder, false);
}
protected static boolean getBooleanParameter(@NotNull String name, @NotNull QueryStringDecoder urlDecoder, boolean defaultValue) {
List<String> values = urlDecoder.parameters().get(name);
if (ContainerUtil.isEmpty(values)) {
return defaultValue;
}
String value = values.get(values.size() - 1);
// if just name specified, so, true
return value.isEmpty() || Boolean.parseBoolean(value);
}
}
@@ -0,0 +1,281 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.ide
import com.google.common.base.Supplier
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import com.google.gson.stream.MalformedJsonException
import com.intellij.ide.IdeBundle
import com.intellij.ide.impl.ProjectUtil.showYesNoDialog
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.util.text.StringUtilRt
import com.intellij.openapi.wm.IdeFocusManager
import com.intellij.ui.AppIcon
import com.intellij.util.ExceptionUtil
import com.intellij.util.io.origin
import com.intellij.util.io.referrer
import com.intellij.util.net.NetUtils
import com.intellij.util.text.nullize
import io.netty.buffer.ByteBufInputStream
import io.netty.buffer.Unpooled
import io.netty.channel.Channel
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.http.*
import org.jetbrains.builtInWebServer.isSignedRequest
import org.jetbrains.io.*
import java.awt.Window
import java.io.IOException
import java.io.OutputStream
import java.lang.reflect.InvocationTargetException
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.URI
import java.net.URISyntaxException
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
/**
* Document your service using [apiDoc](http://apidocjs.com). To extract big example from source code, consider to use *.coffee file near your source file.
* (or Python/Ruby, but coffee recommended because it's plugin is lightweight). See [AboutHttpService] for example.
*
* Don't create JsonReader/JsonWriter directly, use only provided [.createJsonReader], [.createJsonWriter] methods (to ensure that you handle in/out according to REST API guidelines).
*
* @see [Best Practices for Designing a Pragmatic REST API](http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api).
*/
abstract class RestService : HttpRequestHandler() {
companion object {
@JvmField
val LOG = logger<RestService>()
const val PREFIX = "api"
@JvmStatic
protected fun activateLastFocusedFrame() {
(IdeFocusManager.getGlobalInstance().lastFocusedFrame as? Window)?.toFront()
}
@JvmStatic
protected fun createJsonReader(request: FullHttpRequest): JsonReader {
val reader = JsonReader(ByteBufInputStream(request.content()).reader())
reader.isLenient = true
return reader
}
@JvmStatic
protected fun createJsonWriter(out: OutputStream): JsonWriter {
val writer = JsonWriter(out.writer())
writer.setIndent(" ")
return writer
}
@JvmStatic
fun getLastFocusedOrOpenedProject(): Project? {
return IdeFocusManager.getGlobalInstance().lastFocusedFrame?.project ?: ProjectManager.getInstance().openProjects.firstOrNull()
}
@JvmStatic
protected fun sendOk(request: FullHttpRequest, context: ChannelHandlerContext) {
sendStatus(HttpResponseStatus.OK, HttpUtil.isKeepAlive(request), context.channel())
}
@JvmStatic
protected fun sendStatus(status: HttpResponseStatus, keepAlive: Boolean, channel: Channel) {
val response = DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status)
HttpUtil.setContentLength(response, 0)
response.addCommonHeaders()
response.addNoCache()
if (keepAlive) {
HttpUtil.setKeepAlive(response, true)
}
response.headers().set("X-Frame-Options", "Deny")
response.send(channel, !keepAlive)
}
@JvmStatic
protected fun send(byteOut: BufferExposingByteArrayOutputStream, request: HttpRequest, context: ChannelHandlerContext) {
val response = response("application/json", Unpooled.wrappedBuffer(byteOut.internalBuffer, 0, byteOut.size()))
sendResponse(request, context, response)
}
@JvmStatic
protected fun sendResponse(request: HttpRequest, context: ChannelHandlerContext, response: HttpResponse) {
response.addNoCache()
response.headers().set("X-Frame-Options", "Deny")
response.send(context.channel(), request)
}
@Suppress("SameParameterValue")
@JvmStatic
protected fun getStringParameter(name: String, urlDecoder: QueryStringDecoder): String? {
return urlDecoder.parameters().get(name)?.lastOrNull()
}
@JvmStatic
protected fun getIntParameter(name: String, urlDecoder: QueryStringDecoder): Int {
return StringUtilRt.parseInt(getStringParameter(name, urlDecoder).nullize(nullizeSpaces = true), -1)
}
@JvmOverloads
@JvmStatic
protected fun getBooleanParameter(name: String, urlDecoder: QueryStringDecoder, defaultValue: Boolean = false): Boolean {
val values = urlDecoder.parameters().get(name) ?: return defaultValue
// if just name specified, so, true
val value = values.lastOrNull() ?: return true
return value.toBoolean()
}
}
protected val gson: Gson by lazy {
GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.create()
}
private val abuseCounter = CacheBuilder.newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)
.build<InetAddress, AtomicInteger>(CacheLoader.from(Supplier { AtomicInteger() }))
private val trustedOrigins = CacheBuilder.newBuilder()
.maximumSize(1024)
.expireAfterWrite(1, TimeUnit.DAYS)
.build<String, Boolean>()
/**
* Service url must be "/api/$serviceName", but to preserve backward compatibility, prefixless path could be also supported
*/
protected open val isPrefixlessAllowed: Boolean
get() = false
/**
* Use human-readable name or UUID if it is an internal service.
*/
protected abstract fun getServiceName(): String
override fun isSupported(request: FullHttpRequest): Boolean {
if (!isMethodSupported(request.method())) {
return false
}
val uri = request.uri()
if (isPrefixlessAllowed && checkPrefix(uri, getServiceName())) {
return true
}
val serviceName = getServiceName()
val minLength = 1 + PREFIX.length + 1 + serviceName.length
if (uri.length >= minLength &&
uri[0] == '/' &&
uri.regionMatches(1, PREFIX, 0, PREFIX.length, ignoreCase = true) &&
uri.regionMatches(2 + PREFIX.length, serviceName, 0, serviceName.length, ignoreCase = true)) {
if (uri.length == minLength) {
return true
}
else {
val c = uri[minLength]
return c == '/' || c == '?'
}
}
return false
}
protected open fun isMethodSupported(method: HttpMethod): Boolean {
return method === HttpMethod.GET
}
override fun process(urlDecoder: QueryStringDecoder, request: FullHttpRequest, context: ChannelHandlerContext): Boolean {
try {
val counter = abuseCounter.get((context.channel().remoteAddress() as InetSocketAddress).address)
if (counter.incrementAndGet() > Registry.intValue("ide.rest.api.requests.per.minute", 30)) {
HttpResponseStatus.TOO_MANY_REQUESTS.orInSafeMode(HttpResponseStatus.OK).send(context.channel(), request)
return true
}
if (!isHostTrusted(request, urlDecoder)) {
HttpResponseStatus.FORBIDDEN.orInSafeMode(HttpResponseStatus.OK).send(context.channel(), request)
return true
}
val error = execute(urlDecoder, request, context)
if (error != null) {
HttpResponseStatus.BAD_REQUEST.send(context.channel(), request, error)
}
}
catch (e: Throwable) {
val status: HttpResponseStatus?
// JsonReader exception
if (e is MalformedJsonException || e is IllegalStateException && e.message!!.startsWith("Expected a ")) {
LOG.warn(e)
status = HttpResponseStatus.BAD_REQUEST
}
else {
LOG.error(e)
status = HttpResponseStatus.INTERNAL_SERVER_ERROR
}
status.send(context.channel(), request, ExceptionUtil.getThrowableText(e))
}
return true
}
@Throws(InterruptedException::class, InvocationTargetException::class)
protected open fun isHostTrusted(request: FullHttpRequest, urlDecoder: QueryStringDecoder): Boolean {
@Suppress("DEPRECATION")
return isHostTrusted(request)
}
@Deprecated("Use {@link #isHostTrusted(FullHttpRequest, QueryStringDecoder)}")
@Throws(InterruptedException::class, InvocationTargetException::class)
// e.g. upsource trust to configured host
protected open fun isHostTrusted(request: FullHttpRequest): Boolean {
if (request.isSignedRequest()) {
return true
}
val referrer = request.origin ?: request.referrer
val host = try {
if (referrer == null) null else URI(referrer).host.nullize()
}
catch (ignored: URISyntaxException) {
return false
}
if (host != null) {
if (NetUtils.isLocalhost(host)) {
return true
}
else {
trustedOrigins.getIfPresent(host)?.let {
return it
}
}
}
var isTrusted = false
ApplicationManager.getApplication().invokeAndWait({
AppIcon.getInstance().requestAttention(null, true)
isTrusted = showYesNoDialog(IdeBundle.message("warning.use.rest.api", getServiceName(), host ?: "unknown host"), "title.use.rest.api")
if (host != null) {
trustedOrigins.put(host, isTrusted)
}
}, ModalityState.any())
return isTrusted
}
/**
* Return error or send response using [.sendOk], [.send]
*/
@Throws(IOException::class)
abstract fun execute(urlDecoder: QueryStringDecoder, request: FullHttpRequest, context: ChannelHandlerContext): String?
}
@@ -1,4 +1,4 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.util;
import com.intellij.openapi.components.ServiceManager;
@@ -65,7 +65,7 @@ public abstract class PropertiesComponent extends SimpleModificationTracker {
public abstract void setValues(@NonNls @NotNull String name, String[] values);
public static PropertiesComponent getInstance(Project project) {
public static PropertiesComponent getInstance(@NotNull Project project) {
return ServiceManager.getService(project, PropertiesComponent.class);
}
@@ -33,6 +33,7 @@ import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -306,13 +307,23 @@ public class PerformanceWatcher implements Disposable {
for (int i = 0; i < commonPart.size() && i < stackTraceElements.length; i++) {
StackTraceElement el1 = commonPart.get(commonPart.size() - i - 1);
StackTraceElement el2 = stackTraceElements[stackTraceElements.length - i - 1];
if (!el1.equals(el2)) {
if (!compareStackTraceElements(el1, el2)) {
return commonPart.subList(commonPart.size() - i, commonPart.size());
}
}
return commonPart;
}
// same as java.lang.StackTraceElement.equals, but do not care about the line number
private static boolean compareStackTraceElements(StackTraceElement el1, StackTraceElement el2) {
if (el1 == el2) {
return true;
}
return el1.getClassName().equals(el2.getClassName()) &&
Objects.equals(el1.getMethodName(), el2.getMethodName()) &&
Objects.equals(el1.getFileName(), el2.getFileName());
}
private class SwingThreadRunnable implements Runnable {
private final long myCreationMillis;
@@ -424,10 +424,9 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i
DefaultActionGroup actionGroup = new DefaultActionGroup();
if (executionConsole instanceof BuildView) {
actionGroup.addAll(((BuildView)executionConsole).getSwitchActions());
actionGroup.add(new ShowExecutionErrorsOnlyAction((BuildView)executionConsole));
actionGroup.add(BuildTreeFilters.createFilteringActionsGroup((BuildView)executionConsole));
}
DefaultExecutionResult executionResult =
new DefaultExecutionResult(executionConsole, processHandler, actionGroup.getChildren(null));
DefaultExecutionResult executionResult = new DefaultExecutionResult(executionConsole, processHandler, actionGroup.getChildren(null));
executionResult.setRestartActions(restartActions);
return executionResult;
}
@@ -554,7 +554,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
final AtomicInteger counter = new AtomicInteger();
Messages.setTestDialog(new TestDialog() {
@Override
public int show(String message) {
public int show(@NotNull String message) {
counter.set(counter.get() + 1);
return 0;
}
@@ -566,7 +566,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
final AtomicInteger counter = new AtomicInteger();
Messages.setTestDialog(new TestDialog() {
@Override
public int show(String message) {
public int show(@NotNull String message) {
counter.set(counter.get() + 1);
return 1;
}
@@ -32,13 +32,4 @@ public abstract class Expression {
public String getAdvertisingText() {
return null;
}
/**
* @return true if {@link Expression#calculateResult(com.intellij.codeInsight.template.ExpressionContext)} or
* {@link Expression#calculateQuickResult(com.intellij.codeInsight.template.ExpressionContext)}
* require committed PSI for their calculation or false otherwise
*/
public boolean requiresCommittedPSI() {
return true;
}
}
@@ -37,11 +37,6 @@ public class TextExpression extends Expression {
return calculateResult(expressionContext);
}
@Override
public boolean requiresCommittedPSI() {
return false;
}
@Override
public LookupElement[] calculateLookupItems(ExpressionContext expressionContext) {
return LookupElement.EMPTY_ARRAY;
@@ -244,7 +244,7 @@ public abstract class SdkType implements SdkTypeId {
* @param parentComponent the parent component for showing the dialog.
* @param selectedSdk current selected sdk in parentComponent
* @param sdkCreatedCallback the callback to which the created SDK is passed.
* @implSpec method's implementations should not add sdk to the jdkTable neither invoke {@link SdkType#setupSdkPaths}. Only create and
* @implSpec method's implementations should not add sdk to the jdkTable neither invoke {@link SdkType#setupSdkPaths}. Only create and
* and pass to the callback. The rest is done by {@link com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel#setupSdk(Sdk, Consumer)}
*/
public void showCustomCreateUI(@NotNull SdkModel sdkModel,
@@ -64,7 +64,7 @@ public abstract class CodeStyleAbstractPanel implements Disposable, ComponentHig
private final List<TextRange> myPreviewRangesToHighlight = new ArrayList<>();
private final Editor myEditor;
private final EditorEx myEditor;
private final CodeStyleSettings mySettings;
private boolean myShouldUpdatePreview;
protected static final int[] ourWrappings =
@@ -134,7 +134,7 @@ public abstract class CodeStyleAbstractPanel implements Disposable, ComponentHig
}
@Nullable
private Editor createEditor() {
private EditorEx createEditor() {
if (StringUtil.isEmpty(getPreviewText())) return null;
EditorFactory editorFactory = EditorFactory.getInstance();
Document editorDocument = editorFactory.createDocument("");
@@ -159,7 +159,7 @@ public abstract class CodeStyleAbstractPanel implements Disposable, ComponentHig
protected void updatePreview(boolean useDefaultSample) {
if (myEditor == null) return;
updateEditor(useDefaultSample);
updatePreviewHighlighter((EditorEx)myEditor);
updatePreviewHighlighter(myEditor);
}
private void updateEditor(boolean useDefaultSample) {
@@ -167,7 +167,6 @@ public abstract class CodeStyleAbstractPanel implements Disposable, ComponentHig
return;
}
Project project = ProjectUtil.guessCurrentProject(getPanel());
if (myEditor.isDisposed()) return;
if (myLastDocumentModificationStamp != myEditor.getDocument().getModificationStamp()) {
@@ -177,8 +176,19 @@ public abstract class CodeStyleAbstractPanel implements Disposable, ComponentHig
myTextToReformat = StringUtil.convertLineSeparators(ObjectUtils.notNull(getPreviewText(), ""));
}
updateEditorState(true);
}
protected void setEditorText(@NotNull String text, boolean updateHighlighter) {
myTextToReformat = StringUtil.convertLineSeparators(text);
if (updateHighlighter) updatePreviewHighlighter(myEditor);
updateEditorState(false);
}
private void updateEditorState(boolean collectChanges) {
int currOffs = myEditor.getScrollingModel().getVerticalScrollOffset();
CommandProcessor.getInstance().executeCommand(project, () -> replaceText(project), null, null);
Project project = ProjectUtil.guessCurrentProject(getPanel());
CommandProcessor.getInstance().executeCommand(project, () -> replaceText(project, collectChanges), null, null);
myEditor.getSettings().setRightMargin(getAdjustedRightMargin());
myLastDocumentModificationStamp = myEditor.getDocument().getModificationStamp();
@@ -192,11 +202,11 @@ public abstract class CodeStyleAbstractPanel implements Disposable, ComponentHig
protected abstract int getRightMargin();
private void replaceText(final Project project) {
private void replaceText(final Project project, boolean collectChanges) {
ApplicationManager.getApplication().runWriteAction(() -> {
try {
Document beforeReformat = null;
if (myEditor.getDocument().getTextLength() > 0) {
if (collectChanges && myEditor.getDocument().getTextLength() > 0) {
beforeReformat = collectChangesBeforeCurrentSettingsAppliance(project);
}
@@ -596,6 +606,12 @@ public abstract class CodeStyleAbstractPanel implements Disposable, ComponentHig
return myCurrentSettings;
}
@Nullable
protected CodeStyleSettings getModelSettings() {
CodeStyleSchemesModel model = myModel;
return model != null ? model.getCloneSettings(model.getSelectedScheme()) : null;
}
public void setupCopyFromMenu(JPopupMenu copyMenu) {
copyMenu.removeAll();
}
@@ -584,7 +584,7 @@ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPane
}
@Nullable
private CommonCodeStyleSettings.IndentOptions getIndentOptions(CodeStyleSettings settings) {
protected CommonCodeStyleSettings.IndentOptions getIndentOptions(CodeStyleSettings settings) {
return settings.getCommonSettings(getDefaultLanguage()).getIndentOptions();
}
@@ -164,6 +164,7 @@ public class ArrangementGroupingRulesControl extends JBTable {
ArrangementGroupingComponent component = (ArrangementGroupingComponent)value;
component.setRowIndex(row + 1);
component.setHighlight(myRowUnderMouse == row || table.isRowSelected(row));
component.revalidate();
return component;
}
else if (value instanceof ArrangementRepresentationAware) {
@@ -311,12 +311,13 @@
<grid row="1" 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>
<labelFor value="3b679"/>
<text resource-bundle="messages/ApplicationBundle" key="combobox.richcopy.color.scheme"/>
</properties>
</component>
<component id="3b679" class="javax.swing.JComboBox" binding="myRichCopyColorSchemeComboBox">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
@@ -420,7 +421,7 @@
</component>
<component id="87620" class="javax.swing.JComboBox" binding="myStripTrailingSpacesCombo">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
@@ -121,7 +121,7 @@ public abstract class AbstractViewManager implements ViewManager, BuildProgressL
toolbarActions.removeAll();
toolbarActions.addAll(view.createConsoleActions());
toolbarActions.add(new PinBuildViewAction(buildsView));
toolbarActions.add(new ShowExecutionErrorsOnlyAction(view));
toolbarActions.add(BuildTreeFilters.createFilteringActionsGroup(view));
}
@Nullable
@@ -11,6 +11,10 @@ import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.ide.CommonActionsManager;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.OccurenceNavigator;
import com.intellij.ide.OccurenceNavigatorSupport;
import com.intellij.ide.actions.EditSourceAction;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.util.treeView.NodeRenderer;
@@ -56,10 +60,8 @@ import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
@@ -77,7 +79,7 @@ import static com.intellij.util.ui.UIUtil.getTreeSelectionForeground;
/**
* @author Vladislav.Soroka
*/
public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildConsoleView, Filterable<ExecutionNode> {
public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildConsoleView, Filterable<ExecutionNode>, OccurenceNavigator {
private static final Logger LOG = Logger.getInstance(BuildTreeConsoleView.class);
@NonNls private static final String TREE = "tree";
@@ -94,13 +96,14 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
private final Tree myTree;
private final ExecutionNode myRootNode;
private final ExecutionNode myBuildProgressRootNode;
@Nullable
private volatile Predicate<ExecutionNode> myExecutionTreeFilter;
private final Set<Predicate<ExecutionNode>> myNodeFilters;
private final ProblemOccurrenceNavigatorSupport myOccurrenceNavigatorSupport;
public BuildTreeConsoleView(Project project,
BuildDescriptor buildDescriptor,
@Nullable ExecutionConsole executionConsole,
@NotNull BuildViewSettingsProvider buildViewSettingsProvider) {
myNodeFilters = ContainerUtil.newConcurrentSet();
myProject = project;
myWorkingDir = FileUtil.toSystemIndependentName(buildDescriptor.getWorkingDir());
@@ -125,6 +128,9 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
new ConsoleViewHandler(myProject, myTree, myBuildProgressRootNode, this, executionConsole, buildViewSettingsProvider);
myThreeComponentsSplitter.setSecondComponent(myConsoleViewHandler.getComponent());
myPanel.add(myThreeComponentsSplitter, BorderLayout.CENTER);
BuildTreeFilters.install(this);
myRootNode.setFilter(getFilter());
myOccurrenceNavigatorSupport = new ProblemOccurrenceNavigatorSupport(myTree);
}
private void installContextMenu(@NotNull StartBuildEvent startBuildEvent) {
@@ -143,8 +149,14 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
ActionUtil.copyFrom(edit, "EditSource");
group.add(edit);
group.addSeparator();
group.add(new ShowExecutionErrorsOnlyAction(this));
group.addAll(BuildTreeFilters.createFilteringActionsGroup(this));
group.addSeparator();
//Initializing prev and next occurrences actions
final CommonActionsManager actionsManager = CommonActionsManager.getInstance();
final AnAction prevAction = actionsManager.createPrevOccurenceAction(this);
group.add(prevAction);
final AnAction nextAction = actionsManager.createNextOccurenceAction(this);
group.add(nextAction);
PopupHandler.installPopupHandler(myTree, group, "BuildView");
});
}
@@ -162,20 +174,35 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
return true;
}
@NotNull
@Override
@Nullable
public Predicate<ExecutionNode> getFilter() {
return myExecutionTreeFilter;
return executionNode -> executionNode == getBuildProgressRootNode() ||
executionNode.isRunning() ||
executionNode.isFailed() ||
myNodeFilters.stream().anyMatch(predicate -> predicate.test(executionNode));
}
@Override
public void setFilter(@Nullable Predicate<ExecutionNode> executionTreeFilter) {
myExecutionTreeFilter = executionTreeFilter;
ExecutionNode buildProgressRootNode = getBuildProgressRootNode();
public void addFilter(@NotNull Predicate<ExecutionNode> executionTreeFilter) {
myNodeFilters.add(executionTreeFilter);
updateFilter();
}
@Override
public void removeFilter(@NotNull Predicate<ExecutionNode> filter) {
myNodeFilters.remove(filter);
updateFilter();
}
@Override
public boolean contains(@NotNull Predicate<ExecutionNode> filter) {
return myNodeFilters.contains(filter);
}
private void updateFilter() {
ExecutionNode rootElement = getRootElement();
Predicate<ExecutionNode> predicate = executionTreeFilter == null ? null :
node -> node == buildProgressRootNode || executionTreeFilter.test(node);
rootElement.setFilter(predicate);
rootElement.setFilter(getFilter());
scheduleUpdate(rootElement);
}
@@ -315,6 +342,38 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
}
}
@Override
public boolean hasNextOccurence() {
return myOccurrenceNavigatorSupport.hasNextOccurence();
}
@Override
public boolean hasPreviousOccurence() {
return myOccurrenceNavigatorSupport.hasPreviousOccurence();
}
@Override
public OccurenceInfo goNextOccurence() {
return myOccurrenceNavigatorSupport.goNextOccurence();
}
@Override
public OccurenceInfo goPreviousOccurence() {
return myOccurrenceNavigatorSupport.goPreviousOccurence();
}
@NotNull
@Override
public String getNextOccurenceActionName() {
return myOccurrenceNavigatorSupport.getNextOccurenceActionName();
}
@NotNull
@Override
public String getPreviousOccurenceActionName() {
return myOccurrenceNavigatorSupport.getPreviousOccurenceActionName();
}
@NotNull
private static TreeVisitor visitor(@NotNull ExecutionNode executionNode) {
return path -> {
@@ -502,7 +561,13 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
if (eventKind == MessageEvent.Kind.ERROR || eventKind == MessageEvent.Kind.WARNING) {
SimpleNode p = parentNode;
do {
((ExecutionNode)p).reportChildMessageKind(eventKind);
ExecutionNode executionNode = (ExecutionNode)p;
boolean warningUpdate = eventKind == MessageEvent.Kind.WARNING && !executionNode.hasWarnings();
executionNode.reportChildMessageKind(eventKind);
if (warningUpdate) {
executionNode.cleanUpCache();
scheduleUpdate(executionNode);
}
}
while ((p = p.getParent()) instanceof ExecutionNode);
scheduleUpdate(getRootElement());
@@ -745,6 +810,41 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
}
}
private static class ProblemOccurrenceNavigatorSupport extends OccurenceNavigatorSupport {
ProblemOccurrenceNavigatorSupport(final Tree tree) {
super(tree);
}
@Override
protected Navigatable createDescriptorForNode(@NotNull DefaultMutableTreeNode node) {
Object userObject = node.getUserObject();
if (!(userObject instanceof ExecutionNode)) {
return null;
}
final ExecutionNode executionNode = (ExecutionNode)userObject;
if (executionNode.getChildCount() > 0 || !executionNode.hasWarnings() && !executionNode.isFailed()) {
return null;
}
List<Navigatable> navigatables = executionNode.getNavigatables();
if (!navigatables.isEmpty()) {
return navigatables.get(0);
}
return null;
}
@NotNull
@Override
public String getNextOccurenceActionName() {
return IdeBundle.message("action.next.problem");
}
@NotNull
@Override
public String getPreviousOccurenceActionName() {
return IdeBundle.message("action.previous.problem");
}
}
private static class MyTree extends Tree {
private MyTree(TreeModel treemodel) {
super(treemodel);
@@ -32,6 +32,7 @@ import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.ui.actions.CloseAction;
import com.intellij.ide.OccurenceNavigator;
import com.intellij.ide.actions.PinActiveTabAction;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
@@ -56,7 +57,7 @@ import java.util.function.Supplier;
*/
@ApiStatus.Experimental
public class BuildView extends CompositeView<ExecutionConsole>
implements BuildProgressListener, ConsoleView, DataProvider, Filterable<ExecutionNode> {
implements BuildProgressListener, ConsoleView, DataProvider, Filterable<ExecutionNode>, OccurenceNavigator {
public static final String CONSOLE_VIEW_NAME = "consoleView";
private final AtomicReference<StartBuildEvent> myStartBuildEventRef = new AtomicReference<>();
private final BuildDescriptor myBuildDescriptor;
@@ -365,17 +366,75 @@ public class BuildView extends CompositeView<ExecutionConsole>
return getEventView() != null;
}
@NotNull
@Override
public Predicate<ExecutionNode> getFilter() {
BuildTreeConsoleView eventView = getEventView();
return eventView == null ? null : eventView.getFilter();
return eventView == null ? executionNode -> true : eventView.getFilter();
}
@Override
public void setFilter(Predicate<ExecutionNode> filter) {
public void addFilter(@NotNull Predicate<ExecutionNode> filter) {
BuildTreeConsoleView eventView = getEventView();
if (eventView != null) {
eventView.setFilter(filter);
eventView.addFilter(filter);
}
}
@Override
public void removeFilter(@NotNull Predicate<ExecutionNode> filter) {
BuildTreeConsoleView eventView = getEventView();
if (eventView != null) {
eventView.removeFilter(filter);
}
}
@Override
public boolean contains(@NotNull Predicate<ExecutionNode> filter) {
BuildTreeConsoleView eventView = getEventView();
return eventView != null && eventView.contains(filter);
}
@NotNull
private OccurenceNavigator getOccurenceNavigator() {
BuildTreeConsoleView eventView = getEventView();
if (eventView != null) return eventView;
ExecutionConsole executionConsole = getConsoleView();
if (executionConsole instanceof OccurenceNavigator) {
return (OccurenceNavigator)executionConsole;
}
return EMPTY;
}
@Override
public boolean hasNextOccurence() {
return getOccurenceNavigator().hasNextOccurence();
}
@Override
public boolean hasPreviousOccurence() {
return getOccurenceNavigator().hasPreviousOccurence();
}
@Override
public OccurenceInfo goNextOccurence() {
return getOccurenceNavigator().goNextOccurence();
}
@Override
public OccurenceInfo goPreviousOccurence() {
return getOccurenceNavigator().goPreviousOccurence();
}
@NotNull
@Override
public String getNextOccurenceActionName() {
return getOccurenceNavigator().getNextOccurenceActionName();
}
@NotNull
@Override
public String getPreviousOccurenceActionName() {
return getOccurenceNavigator().getPreviousOccurenceActionName();
}
}
@@ -57,7 +57,7 @@ public class ExecutionNode extends CachingSimpleNode {
private static final Icon NODE_ICON_DEFAULT = ICON_16;
private static final Icon NODE_ICON_RUNNING = new AnimatedIcon.FS();
private final Collection<ExecutionNode> myChildrenList = new ConcurrentLinkedDeque<>(); //ContainerUtil.newSmartList();
private final Collection<ExecutionNode> myChildrenList = new ConcurrentLinkedDeque<>();
private final AtomicInteger myErrors = new AtomicInteger();
private final AtomicInteger myWarnings = new AtomicInteger();
private long startTime;
@@ -228,6 +228,11 @@ public class ExecutionNode extends CachingSimpleNode {
return endTime <= 0 && !isSkipped(myResult) && !isFailed(myResult);
}
public boolean hasWarnings() {
return myWarnings.get() > 0 ||
(myResult instanceof MessageEventResult && ((MessageEventResult)myResult).getKind() == MessageEvent.Kind.WARNING);
}
public boolean isFailed() {
return isFailed(myResult) ||
myErrors.get() > 0 ||
@@ -295,25 +300,6 @@ public class ExecutionNode extends CachingSimpleNode {
}
}
ExecutionNode copy(ExecutionNode parent) {
ExecutionNode copy = new ExecutionNode(myProject, parent);
copy.startTime = startTime;
copy.endTime = endTime;
copy.myTitle = myTitle;
copy.myTooltip = myTooltip;
copy.myHint = myHint;
copy.myResult = myResult;
copy.myAutoExpandNode = myAutoExpandNode;
copy.myNavigatable = myNavigatable;
copy.myPreferredIconValue = myPreferredIconValue;
copy.myErrors.set(myErrors.get());
copy.myWarnings.set(myWarnings.get());
copy.myFilter = myFilter;
copy.myName = myName;
copy.myClosedIcon = myClosedIcon;
return copy;
}
private String getCurrentHint() {
String hint = myHint;
int warnings = myWarnings.get();
@@ -1,12 +1,19 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.build;
import org.jetbrains.annotations.NotNull;
import java.util.function.Predicate;
public interface Filterable<T> {
boolean isFilteringEnabled();
@NotNull
Predicate<T> getFilter();
void setFilter(Predicate<T> filter);
void addFilter(@NotNull Predicate<T> filter);
void removeFilter(@NotNull Predicate<T> filter);
boolean contains(@NotNull Predicate<T> filter);
}
@@ -1,61 +0,0 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.build;
import com.intellij.icons.AllIcons;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.util.registry.Registry;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
/**
* @author Vladislav.Soroka
*/
@ApiStatus.Experimental
public class ShowExecutionErrorsOnlyAction extends ToggleAction implements DumbAware {
private static final Predicate<ExecutionNode> ERROR_FILTER = node -> node.isRunning() || node.isFailed();
private final Filterable<ExecutionNode> myFilterable;
private final String mySelectionStateKey;
public ShowExecutionErrorsOnlyAction(@NotNull Filterable<ExecutionNode> filterable) {
this(filterable, "build.toolwindow.show.errors.only.selection.state");
}
public ShowExecutionErrorsOnlyAction(@NotNull Filterable<ExecutionNode> filterable, @Nullable String selectionStateKey) {
super("Show Errors Only", "Show Errors Only", AllIcons.General.Error);
myFilterable = filterable;
mySelectionStateKey = selectionStateKey;
}
@Override
public boolean isSelected(@NotNull AnActionEvent e) {
final Presentation presentation = e.getPresentation();
if (!Registry.is("build.view.side-by-side", true)) {
presentation.setVisible(false);
return false;
}
boolean filteringEnabled = myFilterable.isFilteringEnabled();
presentation.setEnabledAndVisible(filteringEnabled);
if (filteringEnabled && mySelectionStateKey != null &&
PropertiesComponent.getInstance().getBoolean(mySelectionStateKey, true) &&
myFilterable.getFilter() != ERROR_FILTER) {
setSelected(e, true);
}
return myFilterable.getFilter() == ERROR_FILTER;
}
@Override
public void setSelected(@NotNull AnActionEvent e, boolean state) {
myFilterable.setFilter(state ? ERROR_FILTER : null);
if (mySelectionStateKey != null) {
PropertiesComponent.getInstance().setValue(mySelectionStateKey, state, true);
}
}
}
@@ -0,0 +1,103 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
@file:JvmName("BuildTreeFilters")
package com.intellij.build
import com.intellij.icons.AllIcons
import com.intellij.ide.util.PropertiesComponent
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.DefaultActionGroup
import com.intellij.openapi.actionSystem.ToggleAction
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.util.registry.Registry
import org.jetbrains.annotations.ApiStatus
import java.util.function.Predicate
private val SUCCESSFUL_STEPS_FILTER = Predicate { node: ExecutionNode -> !node.isFailed && !node.hasWarnings() }
private val WARNINGS_FILTER = Predicate { node: ExecutionNode -> node.hasWarnings() }
@ApiStatus.Experimental
fun createFilteringActionsGroup(filterable: Filterable<ExecutionNode>): DefaultActionGroup {
val actionGroup = DefaultActionGroup("Filters", true)
actionGroup.templatePresentation.icon = AllIcons.Actions.Show
actionGroup.add(WarningsToggleAction(filterable))
actionGroup.add(SuccessfulStepsToggleAction(filterable))
return actionGroup
}
@ApiStatus.Experimental
fun install(filterable: Filterable<ExecutionNode>) {
val filteringEnabled = filterable.isFilteringEnabled
if (!filteringEnabled) return
SuccessfulStepsToggleAction.install(filterable)
WarningsToggleAction.install(filterable)
}
@ApiStatus.Experimental
open class FilterToggleAction constructor(text: String,
private val stateKey: String?,
private val filterable: Filterable<ExecutionNode>,
private val filter: Predicate<ExecutionNode>,
private val defaultState: Boolean) : ToggleAction(text), DumbAware {
override fun isSelected(e: AnActionEvent): Boolean {
val presentation = e.presentation
if (!Registry.`is`("build.view.side-by-side", true)) {
presentation.isVisible = false
return false
}
val filteringEnabled = filterable.isFilteringEnabled
presentation.isEnabledAndVisible = filteringEnabled
if (filteringEnabled && stateKey != null &&
PropertiesComponent.getInstance().getBoolean(stateKey, defaultState) &&
!filterable.contains(filter)) {
setSelected(e, true)
}
return filterable.contains(filter)
}
override fun setSelected(e: AnActionEvent, state: Boolean) {
if (state) {
filterable.addFilter(filter)
}
else {
filterable.removeFilter(filter)
}
if (stateKey != null) {
PropertiesComponent.getInstance().setValue(stateKey, state, defaultState)
}
}
companion object {
fun install(filterable: Filterable<ExecutionNode>,
filter: Predicate<ExecutionNode>,
stateKey: String,
defaultState: Boolean) {
if (PropertiesComponent.getInstance().getBoolean(stateKey, defaultState) &&
!filterable.contains(filter)) {
filterable.addFilter(filter)
}
}
}
}
@ApiStatus.Experimental
class SuccessfulStepsToggleAction(filterable: Filterable<ExecutionNode>) :
FilterToggleAction("Show Successful Steps", STATE_KEY, filterable, SUCCESSFUL_STEPS_FILTER, false), DumbAware {
companion object {
private const val STATE_KEY = "build.toolwindow.show.successful.steps.selection.state"
fun install(filterable: Filterable<ExecutionNode>) {
install(filterable, SUCCESSFUL_STEPS_FILTER, STATE_KEY, false)
}
}
}
@ApiStatus.Experimental
class WarningsToggleAction(filterable: Filterable<ExecutionNode>) :
FilterToggleAction("Show Warnings", STATE_KEY, filterable, WARNINGS_FILTER, true), DumbAware {
companion object {
private const val STATE_KEY = "build.toolwindow.show.warnings.selection.state"
fun install(filterable: Filterable<ExecutionNode>) {
install(filterable, WARNINGS_FILTER, STATE_KEY, true)
}
}
}
@@ -6,6 +6,7 @@ import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.navigation.ChooseByNameContributor;
import com.intellij.navigation.ChooseByNameContributorEx;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileNameMatcher;
@@ -33,9 +34,10 @@ import com.intellij.psi.impl.source.resolve.reference.impl.providers.*;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScope;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.FindSymbolParameters;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -116,13 +118,15 @@ public class FilePathCompletionContributor extends CompletionContributor {
if (contextFile != null) {
final String[] fileNames = getAllNames(project);
final Set<String> resultNames = new TreeSet<>();
for (String fileName : fileNames) {
if (filenameMatchesPrefixOrType(fileName, prefix, set.getSuitableFileTypes(), parameters.getInvocationCount())) {
Set<String> resultNames = new TreeSet<>();
String finalPrefix = prefix;
processAllNames(project, fileName -> {
if (filenameMatchesPrefixOrType(fileName, finalPrefix, set.getSuitableFileTypes(),
parameters.getInvocationCount())) {
resultNames.add(fileName);
}
}
return true;
});
final ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex();
@@ -180,16 +184,19 @@ public class FilePathCompletionContributor extends CompletionContributor {
extend(CompletionType.BASIC, psiElement(), provider);
}
private static boolean filenameMatchesPrefixOrType(final String fileName, final String prefix, final FileType[] suitableFileTypes, final int invocationCount) {
final boolean prefixMatched = prefix.length() == 0 || StringUtil.startsWithIgnoreCase(fileName, prefix);
private static boolean filenameMatchesPrefixOrType(String fileName,
String prefix,
FileType[] suitableFileTypes,
int invocationCount) {
boolean prefixMatched = prefix.length() == 0 || StringUtil.startsWithIgnoreCase(fileName, prefix);
if (prefixMatched && (suitableFileTypes.length == 0 || invocationCount > 2)) return true;
if (prefixMatched) {
final String extension = FileUtilRt.getExtension(fileName);
String extension = FileUtilRt.getExtension(fileName);
if (extension.length() == 0) return false;
for (final FileType fileType : suitableFileTypes) {
for (final FileNameMatcher matcher : FileTypeManager.getInstance().getAssociations(fileType)) {
for (FileType fileType : suitableFileTypes) {
for (FileNameMatcher matcher : FileTypeManager.getInstance().getAssociations(fileType)) {
if (FileNameMatcherEx.acceptsCharSequence(matcher, fileName)) return true;
}
}
@@ -237,12 +244,15 @@ public class FilePathCompletionContributor extends CompletionContributor {
return true;
}
private static String[] getAllNames(@NotNull final Project project) {
Set<String> names = new HashSet<>();
final ChooseByNameContributor[] nameContributors = ChooseByNameContributor.FILE_EP_NAME.getExtensions();
for (final ChooseByNameContributor contributor : nameContributors) {
private static void processAllNames(@NotNull Project project, @NotNull Processor<String> processor) {
for (ChooseByNameContributor contributor : ChooseByNameContributor.FILE_EP_NAME.getExtensionList()) {
try {
ContainerUtil.addAll(names, contributor.getNames(project, false));
if (contributor instanceof ChooseByNameContributorEx) {
((ChooseByNameContributorEx)contributor).processNames(processor, FindSymbolParameters.searchScopeFor(project, false), null);
}
else {
ContainerUtil.process(contributor.getNames(project, false), processor);
}
}
catch (ProcessCanceledException ex) {
// index corruption detected, ignore
@@ -251,8 +261,6 @@ public class FilePathCompletionContributor extends CompletionContributor {
LOG.error(ex);
}
}
return ArrayUtil.toStringArray(names);
}
@Nullable
@@ -38,11 +38,6 @@ public class EmptyExpression extends Expression {
return null;
}
@Override
public boolean requiresCommittedPSI() {
return false;
}
@Override
public LookupElement[] calculateLookupItems(ExpressionContext context) {
return null;
@@ -340,7 +340,7 @@ public class IntentionHintComponent implements Disposable, ScrollAwareHint {
if (!e.isPopupTrigger() && e.getButton() == MouseEvent.BUTTON1) {
AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_SHOW_INTENTION_ACTIONS);
AnActionEvent event = AnActionEvent.createFromInputEvent(e, ActionPlaces.MOUSE_SHORTCUT, null, SimpleDataContext.getProjectContext(project));
ActionsCollector.getInstance().record(project, action, event, null);
ActionsCollector.getInstance().record(project, action, event, file.getLanguage());
showPopup(true);
}
@@ -39,11 +39,6 @@ public class ConstantNode extends Expression {
return myValue;
}
@Override
public boolean requiresCommittedPSI() {
return false;
}
@Override
public LookupElement[] calculateLookupItems(ExpressionContext context) {
return LookupElement.EMPTY_ARRAY;
@@ -35,11 +35,6 @@ public class EmptyNode extends Expression {
return null;
}
@Override
public boolean requiresCommittedPSI() {
return false;
}
@Override
public LookupElement[] calculateLookupItems(ExpressionContext context) {
return null;
@@ -45,8 +45,4 @@ public class SelectionNode extends Expression {
return calculateQuickResult(context);
}
@Override
public boolean requiresCommittedPSI() {
return false;
}
}
@@ -832,13 +832,11 @@ public class TemplateState implements Disposable {
int start = mySegments.getSegmentStart(segmentNumber);
int end = mySegments.getSegmentEnd(segmentNumber);
if(!isQuick || expressionNode.requiresCommittedPSI()) {
PsiDocumentManager.getInstance(myProject).commitDocument(myDocument);
}
PsiDocumentManager.getInstance(myProject).commitDocument(myDocument);
PsiFile psiFile = getPsiFile();
PsiElement element = psiFile != null ? psiFile.findElementAt(start) : null;
if (element != null && !element.isValid()) {
element = null;
if (element != null) {
PsiUtilCore.ensureValid(element);
}
ExpressionContext context = createExpressionContext(start);
@@ -860,8 +858,8 @@ public class TemplateState implements Disposable {
if (defaultValue != null && resultIsNullOrEmpty) {
result = defaultValue.calculateResult(context);
}
if (element != null && !element.isValid()) {
element = null;
if (element != null) {
PsiUtilCore.ensureValid(element);
}
if (result == null || result.equalsToText(oldValue, element)) return;
@@ -47,11 +47,6 @@ public class VariableNode extends Expression {
return TemplateManagerImpl.getTemplateState(context.getEditor()).getVariableValue(getName());
}
@Override
public boolean requiresCommittedPSI() {
return myInitialValue != null && myInitialValue.requiresCommittedPSI();
}
@Override
public LookupElement[] calculateLookupItems(ExpressionContext context) {
if (myInitialValue == null){
@@ -332,7 +332,8 @@ public class ExecutorRegistryImpl extends ExecutorRegistry implements Disposable
if (configuration instanceof CompoundRunConfiguration) {
RunManager runManager = RunManager.getInstance(project);
for (SettingsAndEffectiveTarget settingsAndEffectiveTarget : ((CompoundRunConfiguration)configuration).getConfigurationsWithEffectiveRunTargets()) {
run(project, settingsAndEffectiveTarget.getConfiguration(), runManager.findSettings(configuration), dataContext);
RunConfiguration subConfiguration = settingsAndEffectiveTarget.getConfiguration();
run(project, subConfiguration, runManager.findSettings(subConfiguration), dataContext);
}
}
else {
@@ -349,7 +349,7 @@ public class SearchEverywhereUI extends BigPopupUI implements DataProvider, Quic
@NotNull
@Override
public AnAction[] getChildren(@Nullable AnActionEvent e) {
if (e == null) return EMPTY_ARRAY;
if (e == null || mySelectedTab == null) return EMPTY_ARRAY;
return mySelectedTab.actions.toArray(EMPTY_ARRAY);
}
});
@@ -424,7 +424,6 @@ public class SearchEverywhereUI extends BigPopupUI implements DataProvider, Quic
contributorsPanel.add(tab);
myTabs.add(tab);
});
switchToTab(allTab);
return contributorsPanel;
}
@@ -1427,8 +1426,8 @@ public class SearchEverywhereUI extends BigPopupUI implements DataProvider, Quic
@Override
public void update(@NotNull AnActionEvent e) {
Boolean enabled = mySelectedTab.getContributor().map(contributor -> contributor.showInFindResults()).orElse(true);
e.getPresentation().setEnabled(enabled);
SearchEverywhereContributor<?> contributor = mySelectedTab == null ? null : mySelectedTab.contributor;
e.getPresentation().setEnabled(contributor == null || contributor.showInFindResults());
}
}
@@ -8,7 +8,11 @@ import com.intellij.ide.scratch.RootType;
import com.intellij.ide.scratch.ScratchFileService;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginDescriptor;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.io.FileUtil;
@@ -19,6 +23,7 @@ import com.intellij.util.ObjectUtils;
import com.intellij.util.PlatformUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.DigestUtil;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -28,8 +33,10 @@ import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* <p> Extensions root type provide a common interface for plugins to access resources that are modifiable by the user. </p>
@@ -191,17 +198,24 @@ public class ExtensionsRootType extends RootType {
private static List<URL> getBundledResourceUrls(@NotNull PluginId pluginId, @NotNull String path) throws IOException {
String resourcesPath = EXTENSIONS_PATH + "/" + path;
IdeaPluginDescriptor plugin = PluginManager.getPlugin(pluginId);
ClassLoader pluginClassLoader = plugin != null ? plugin.getPluginClassLoader() : null;
Set<URL> urls = plugin == null ? null : ContainerUtil.newLinkedHashSet(ContainerUtil.toList(pluginClassLoader.getResources(resourcesPath)));
if (urls == null) return ContainerUtil.emptyList();
if (plugin == null) return ContainerUtil.emptyList();
ClassLoader pluginClassLoader = plugin.getPluginClassLoader();
final Enumeration<URL> resources = pluginClassLoader.getResources(resourcesPath);
if (resources == null) return ContainerUtil.emptyList();
if (plugin.getUseIdeaClassLoader()) return ContainerUtil.toList(resources);
PluginId corePluginId = PluginId.findId(PluginManagerCore.CORE_PLUGIN_ID);
IdeaPluginDescriptor corePlugin = ObjectUtils.notNull(PluginManager.getPlugin(corePluginId));
ClassLoader coreClassLoader = corePlugin.getPluginClassLoader();
if (coreClassLoader != pluginClassLoader && !plugin.getUseIdeaClassLoader() && !pluginId.equals(corePluginId)) {
urls.removeAll(ContainerUtil.toList(coreClassLoader.getResources(resourcesPath)));
final Set<URL> urls = ContainerUtil.newLinkedHashSet(ContainerUtil.toList(resources));
// exclude parent classloader resources from list
final List<ClassLoader> dependentPluginClassLoaders = StreamEx.of(plugin.getDependentPluginIds())
.map(PluginManager::getPlugin)
.nonNull()
.map(PluginDescriptor::getPluginClassLoader)
.without(pluginClassLoader)
.collect(Collectors.toList());
for (ClassLoader classLoader : dependentPluginClassLoaders) {
urls.removeAll(ContainerUtil.toList(classLoader.getResources(resourcesPath)));
}
return ContainerUtil.newArrayList(urls);
}
@@ -269,13 +283,23 @@ public class ExtensionsRootType extends RootType {
FileUtil.rename(file, newName);
}
private void extractBundledExtensionsIfNeeded(@NotNull PluginId pluginId) throws IOException {
if (!ApplicationManager.getApplication().isDispatchThread()) return;
private void extractBundledExtensionsIfNeeded(@NotNull PluginId pluginId) {
IdeaPluginDescriptor plugin = PluginManager.getPlugin(pluginId);
if (plugin == null || !ResourceVersions.getInstance().shouldUpdateResourcesOf(plugin)) return;
extractBundledResources(pluginId, "");
ResourceVersions.getInstance().resourcesUpdated(plugin);
Task.Backgroundable extractResourcesInBackground =
new Task.Backgroundable(null, "Extracting bundled extensions for plugin: " + pluginId.getIdString()) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
try {
extractBundledResources(pluginId, "");
ApplicationManager.getApplication().invokeLater(() -> ResourceVersions.getInstance().resourcesUpdated(plugin));
}
catch (IOException ex) {
LOG.warn("Failed to extract bundled extensions for plugin: " + plugin.getName(), ex);
}
}
};
ProgressManager.getInstance().run(extractResourcesInBackground);
}
}
@@ -4,8 +4,12 @@ package com.intellij.ide.extensionResources;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
@@ -29,11 +33,20 @@ public class RestoreBundledExtensionsAction extends DumbAwareAction {
assert file != null && pluginId != null && path != null;
try {
extensionsRootType.extractBundledResources(pluginId, path);
}
catch (IOException ex) {
ExtensionsRootType.LOG.warn("Failed to extract bundled extensions for " + file.getPath(), ex);
}
Task.Backgroundable extractResourcesInBackground = new Task.Backgroundable(
e.getProject(),
"Extracting bundled extensions for plugin: " + pluginId.getIdString()) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
try {
extensionsRootType.extractBundledResources(pluginId, path);
VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
}
catch (IOException ex) {
ExtensionsRootType.LOG.warn("Failed to extract bundled extensions for " + file.getPath(), ex);
}
}
};
ProgressManager.getInstance().run(extractResourcesInBackground);
}
}
@@ -16,6 +16,10 @@ import com.intellij.openapi.progress.util.ProgressIndicatorBase;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.PomTargetPsiElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.Processors;
@@ -180,7 +184,8 @@ public abstract class ContributorsBasedGotoByModel implements ChooseByNameModelE
if (LOG.isDebugEnabled()) {
LOG.debug(System.currentTimeMillis() - contributorStarted + "," + contributor + ",");
}
} else {
}
else {
NavigationItem[] itemsByName = contributor.getItemsByName(name, parameters.getLocalPatternName(), myProject, searchInLibraries);
for (NavigationItem item : itemsByName) {
canceled.checkCanceled();
@@ -188,6 +193,9 @@ public abstract class ContributorsBasedGotoByModel implements ChooseByNameModelE
PluginException.logPluginError(LOG, "null item from contributor " + contributor + " for name " + name, null, contributor.getClass());
continue;
}
VirtualFile file = item instanceof PsiElement && !(item instanceof PomTargetPsiElement)
? PsiUtilCore.getVirtualFile((PsiElement)item) : null;
if (file != null && !parameters.getSearchScope().contains(file)) continue;
if (acceptItem(item)) {
items.add(item);
@@ -19,49 +19,18 @@ import com.intellij.navigation.ChooseByNameContributorEx;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.Processors;
import com.intellij.util.indexing.FindSymbolParameters;
import com.intellij.util.indexing.IdFilter;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class DefaultFileNavigationContributor implements ChooseByNameContributorEx, DumbAware {
private static final Logger LOG = Logger.getInstance(DefaultFileNavigationContributor.class);
@Override
@NotNull
public String[] getNames(Project project, boolean includeNonProjectItems) {
THashSet<String> names = new THashSet<>(1000);
IdFilter filter = IdFilter.getProjectIdFilter(project, includeNonProjectItems);
processNames(s -> {
names.add(s);
return true;
}, FindSymbolParameters.searchScopeFor(project, includeNonProjectItems), filter);
if (LOG.isDebugEnabled()) {
LOG.debug("All names retrieved2:" + names.size());
}
return ArrayUtil.toStringArray(names);
}
@Override
@NotNull
public NavigationItem[] getItemsByName(String name, final String pattern, Project project, boolean includeNonProjectItems) {
List<NavigationItem> result = new ArrayList<>();
Processor<NavigationItem> processor = Processors.cancelableCollectProcessor(result);
processElementsWithName(name, processor, FindSymbolParameters.wrap(pattern, project, includeNonProjectItems));
return result.isEmpty() ? NavigationItem.EMPTY_NAVIGATION_ITEM_ARRAY : result.toArray(NavigationItem.EMPTY_NAVIGATION_ITEM_ARRAY);
}
@Override
public void processNames(@NotNull final Processor<String> processor, @NotNull GlobalSearchScope scope, IdFilter filter) {
@@ -15,13 +15,18 @@
*/
package com.intellij.navigation;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.indexing.FindSymbolParameters;
import com.intellij.util.indexing.IdFilter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public interface ChooseByNameContributorEx extends ChooseByNameContributor {
void processNames(@NotNull Processor<String> processor,
@@ -31,4 +36,24 @@ public interface ChooseByNameContributorEx extends ChooseByNameContributor {
void processElementsWithName(@NotNull String name,
@NotNull Processor<NavigationItem> processor,
@NotNull FindSymbolParameters parameters);
/** @deprecated Use {@link #processNames(Processor, GlobalSearchScope, IdFilter)} instead */
@Deprecated
@Override
@NotNull
default String[] getNames(Project project, boolean includeNonProjectItems) {
List<String> result = new ArrayList<>();
processNames(result::add, FindSymbolParameters.searchScopeFor(project, includeNonProjectItems), null);
return ArrayUtil.toStringArray(result);
}
/** @deprecated Use {@link #processElementsWithName(String, Processor, FindSymbolParameters)} instead */
@Deprecated
@Override
@NotNull
default NavigationItem[] getItemsByName(String name, String pattern, Project project, boolean includeNonProjectItems) {
List<NavigationItem> result = new ArrayList<>();
processElementsWithName(name, result::add, FindSymbolParameters.simple(project, includeNonProjectItems));
return result.isEmpty() ? NavigationItem.EMPTY_NAVIGATION_ITEM_ARRAY : result.toArray(NavigationItem.EMPTY_NAVIGATION_ITEM_ARRAY);
}
}
@@ -25,7 +25,7 @@ import com.intellij.openapi.wm.IdeFocusManager
import java.io.File
import java.util.regex.Pattern
class JBProtocolNavigateCommand : JBProtocolCommand(NAVIGATE_COMMAND) {
internal class JBProtocolNavigateCommand : JBProtocolCommand(NAVIGATE_COMMAND) {
override fun perform(target: String, parameters: Map<String, String>) {
// handles URLs of the following types:
@@ -255,7 +255,7 @@ public class DisposerDebugger implements UiDebuggerExtension, Disposable {
}
private void queueUpdate() {
UIUtil.invokeLaterIfNeeded(() -> myTreeBuilder.refilter());
UIUtil.invokeLaterIfNeeded(() -> myTreeBuilder.refilterAsync());
}
@Override
@@ -275,7 +275,7 @@ public class DisposerDebugger implements UiDebuggerExtension, Disposable {
public void clear() {
myModificationToFilter = Disposer.getTree().getModification();
myTreeBuilder.refilter();
myTreeBuilder.refilterAsync();
}
}
@@ -5,7 +5,6 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.FileContent;
import com.intellij.util.indexing.ID;
import com.intellij.util.indexing.impl.InputData;
import com.intellij.util.indexing.impl.InputDataDiffBuilder;
import com.intellij.util.indexing.impl.forward.AbstractForwardIndexAccessor;
import com.intellij.util.io.DataExternalizer;
@@ -20,7 +19,7 @@ import java.io.IOException;
import java.util.Collections;
import java.util.Map;
class StubUpdatingForwardIndexAccessor extends AbstractForwardIndexAccessor<Integer, SerializedStubTree, IndexedStubs> {
class StubUpdatingForwardIndexAccessor extends AbstractForwardIndexAccessor<Integer, SerializedStubTree, IndexedStubs , FileContent> {
StubUpdatingForwardIndexAccessor() {super(new DataExternalizer<IndexedStubs>() {
private volatile boolean myEnsuredStubElementTypesLoaded;
@@ -69,10 +68,10 @@ class StubUpdatingForwardIndexAccessor extends AbstractForwardIndexAccessor<Inte
}
});}
@Nullable
@Override
public IndexedStubs convertToDataType(@NotNull InputData<Integer, SerializedStubTree> data) {
return getIndexedStubs(data.getKeyValues());
public IndexedStubs convertToDataType(@Nullable Map<Integer, SerializedStubTree> map,
@Nullable FileContent content) {
return getIndexedStubs(map);
}
@Override
@@ -97,11 +97,6 @@ public class MyLookupExpression extends Expression {
return new TextResult(myName);
}
@Override
public boolean requiresCommittedPSI() {
return false;
}
@Override
public String getAdvertisingText() {
return myAdvertisementText;
@@ -7,7 +7,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.EverythingGlobalScope;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScope;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -69,12 +68,12 @@ public class FindSymbolParameters {
}
public static FindSymbolParameters wrap(@NotNull String pattern, @NotNull Project project, boolean searchInLibraries) {
return new FindSymbolParameters(pattern, pattern, searchScopeFor(project, searchInLibraries), null);
return new FindSymbolParameters(pattern, pattern, searchScopeFor(project, searchInLibraries),
IdFilter.getProjectIdFilter(project, searchInLibraries));
}
public static FindSymbolParameters wrap(@NotNull String pattern, @NotNull GlobalSearchScope scope) {
IdFilter idFilter = IdFilter.getProjectIdFilter(ObjectUtils.notNull(scope.getProject()), scope.isSearchInLibraries());
return new FindSymbolParameters(pattern, pattern, scope, idFilter);
return new FindSymbolParameters(pattern, pattern, scope, null);
}
public static FindSymbolParameters simple(@NotNull Project project, boolean searchInLibraries) {
@@ -1,7 +1,6 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.util.indexing;
import com.intellij.util.indexing.impl.InputData;
import com.intellij.util.indexing.impl.InputDataDiffBuilder;
import com.intellij.util.indexing.impl.MapInputDataDiffBuilder;
import com.intellij.util.indexing.impl.forward.AbstractMapForwardIndexAccessor;
@@ -14,8 +13,8 @@ import java.io.IOException;
import java.util.Map;
class HashIdForwardIndexAccessor<Key, Value, Input>
extends AbstractMapForwardIndexAccessor<Key, Value, Integer>
implements IntForwardIndexAccessor<Key, Value> {
extends AbstractMapForwardIndexAccessor<Key, Value, Integer, Input>
implements IntForwardIndexAccessor<Key, Value, Input> {
private final UpdatableSnapshotInputMappingIndex<Key, Value, Input> mySnapshotInputMappingIndex;
HashIdForwardIndexAccessor(@NotNull UpdatableSnapshotInputMappingIndex<Key, Value, Input> snapshotInputMappingIndex) {
@@ -36,13 +35,12 @@ class HashIdForwardIndexAccessor<Key, Value, Input>
}
@Override
public int serializeIndexedDataToInt(@NotNull InputData<Key, Value> data) {
return data == InputData.empty() ? 0 : ((HashedInputData)data).getHashId();
}
@Nullable
@Override
public Integer convertToDataType(@NotNull InputData<Key, Value> data) {
return serializeIndexedDataToInt(data);
public int convertToInt(@Nullable Map<Key, Value> map, @Nullable Input content) {
try {
return mySnapshotInputMappingIndex.getHashId(content);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@@ -1,20 +0,0 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.util.indexing;
import com.intellij.util.indexing.impl.InputData;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class HashedInputData<Key, Value> extends InputData<Key, Value> {
private final int myHashId;
protected HashedInputData(@NotNull Map<Key, Value> values, int hashId) {
super(values);
myHashId = hashId;
}
public int getHashId() {
return myHashId;
}
}
@@ -26,10 +26,10 @@ public class SharedMapForwardIndex implements ForwardIndex {
// only verification purpose
@Nullable
private final AbstractForwardIndexAccessor<?, ?, ?> myAccessor;
private final AbstractForwardIndexAccessor<?, ?, ?, ?> myAccessor;
public SharedMapForwardIndex(@NotNull IndexExtension<?, ?, ?> extension,
@Nullable AbstractForwardIndexAccessor<?, ?, ?> accessor,
@Nullable AbstractForwardIndexAccessor<?, ?, ?, ?> accessor,
@Nullable File verificationIndexStorageFile,
boolean verificationIndexHasChunks) throws IOException {
myIndexId = (ID<?, ?>)extension.getName();
@@ -1,7 +1,6 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.util.indexing;
import com.intellij.util.indexing.impl.InputData;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -13,5 +12,5 @@ import java.util.Map;
@ApiStatus.Experimental
public interface SnapshotInputMappingIndex<Key, Value, Input> extends Closeable {
@Nullable
InputData<Key, Value> readData(@NotNull Input content) throws IOException;
Map<Key, Value> readData(@NotNull Input content) throws IOException;
}
@@ -13,7 +13,6 @@ import com.intellij.util.CompressionUtil;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.SystemProperties;
import com.intellij.util.indexing.impl.DebugAssertions;
import com.intellij.util.indexing.impl.InputData;
import com.intellij.util.indexing.impl.forward.AbstractForwardIndexAccessor;
import com.intellij.util.indexing.impl.forward.PersistentMapBasedForwardIndex;
import com.intellij.util.io.*;
@@ -71,13 +70,12 @@ class SnapshotInputMappings<Key, Value, Input> implements UpdatableSnapshotInput
@Nullable
@Override
public InputData<Key, Value> readData(@NotNull Input content) throws IOException {
public Map<Key, Value> readData(@NotNull Input content) throws IOException {
Map<Key, Value> data = null;
int hashId = 0;
if (doReadSavedPersistentData) {
if (myContents == null || !myContents.isBusyReading() || DebugAssertions.EXTRA_SANITY_CHECKS) { // avoid blocking read, we can calculate index value
hashId = getHashId(content);
int hashId = getHashId(content);
ByteArraySequence bytes = readContents(hashId);
if (bytes != null) {
@@ -98,32 +96,25 @@ class SnapshotInputMappings<Key, Value, Input> implements UpdatableSnapshotInput
}
}
}
return data == null ? null : new HashedInputData<>(data, hashId);
return data;
}
@Override
public InputData<Key, Value> putData(@Nullable Input content, @NotNull InputData<Key, Value> data) throws IOException {
int hashId;
InputData<Key, Value> result;
if (data instanceof HashedInputData) {
hashId = ((HashedInputData<Key, Value>)data).getHashId();
result = data;
} else {
hashId = getHashId(content);
result = hashId == 0 ? InputData.empty() : new HashedInputData<>(data.getKeyValues(), hashId);
}
boolean saved = savePersistentData(data.getKeyValues(), hashId);
public void putData(@Nullable Input content, @NotNull Map<Key, Value> data) throws IOException {
int hashId = getHashId(content);
boolean saved = savePersistentData(data, hashId);
if (DebugAssertions.EXTRA_SANITY_CHECKS) {
if (saved) {
try {
myIndexingTrace.put(hashId, getContentDebugData(content) + "," + ExceptionUtil.getThrowableText(new Throwable()));
myIndexingTrace.put(hashId, getContentDebugData(content) +
"," +
ExceptionUtil.getThrowableText(new Throwable()));
}
catch (IOException ex) {
LOG.error(ex);
}
}
}
return result;
}
@NotNull
@@ -132,7 +123,8 @@ class SnapshotInputMappings<Key, Value, Input> implements UpdatableSnapshotInput
return "[" + content.getFile().getPath() + ";" + content.getFileType().getName() + ";" + content.getCharset() + "]";
}
private int getHashId(@Nullable Input content) throws IOException {
@Override
public int getHashId(@Nullable Input content) throws IOException {
return content == null ? 0 : getHashOfContent((FileContent) content);
}
@@ -1,7 +1,6 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.util.indexing;
import com.intellij.util.indexing.impl.InputData;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -14,7 +13,9 @@ public interface UpdatableSnapshotInputMappingIndex<Key, Value, Input> extends S
@NotNull
Map<Key, Value> readData(int hashId) throws IOException;
InputData<Key, Value> putData(@NotNull Input content, @NotNull InputData<Key, Value> data) throws IOException;
void putData(@NotNull Input content, @NotNull Map<Key, Value> data) throws IOException;
int getHashId(@Nullable Input content) throws IOException;
void flush() throws IOException;
@@ -72,7 +72,7 @@ public class VfsAwareMapReduceIndex<Key, Value, Input> extends MapReduceIndex<Ke
protected VfsAwareMapReduceIndex(@NotNull IndexExtension<Key, Value, Input> extension,
@NotNull IndexStorage<Key, Value> storage,
@Nullable ForwardIndex forwardIndexMap,
@Nullable ForwardIndexAccessor<Key, Value> forwardIndexAccessor,
@Nullable ForwardIndexAccessor<Key, Value, ?, Input> forwardIndexAccessor,
@Nullable SnapshotInputMappingIndex<Key, Value, Input> snapshotInputMappings) {
super(extension, storage, forwardIndexMap, forwardIndexAccessor, null);
SharedIndicesData.registerIndex((ID<Key, Value>)myIndexId, extension);
@@ -89,8 +89,8 @@ public class VfsAwareMapReduceIndex<Key, Value, Input> extends MapReduceIndex<Ke
@NotNull
@Override
protected InputData<Key, Value> mapInput(@Nullable Input content) {
InputData<Key, Value> data;
protected Map<Key, Value> mapInput(@Nullable Input content) {
Map<Key, Value> data;
boolean containsSnapshotData = true;
if (mySnapshotInputMappings != null && !myInMemoryMode.get() && content != null) {
try {
@@ -108,7 +108,7 @@ public class VfsAwareMapReduceIndex<Key, Value, Input> extends MapReduceIndex<Ke
data = super.mapInput(content);
if (!containsSnapshotData) {
try {
return ((UpdatableSnapshotInputMappingIndex)mySnapshotInputMappings).putData(content, data);
((UpdatableSnapshotInputMappingIndex)mySnapshotInputMappings).putData(content, data);
}
catch (IOException e) {
throw new RuntimeException(e);
@@ -140,13 +140,13 @@ public class VfsAwareMapReduceIndex<Key, Value, Input> extends MapReduceIndex<Ke
}
@Override
protected void updateForwardIndex(int inputId, @NotNull InputData<Key, Value> data) throws IOException {
protected void updateForwardIndex(int inputId, @NotNull Map<Key, Value> data, @Nullable Object forwardIndexData) throws IOException {
if (myInMemoryMode.get()) {
synchronized (myInMemoryKeysAndValues) {
myInMemoryKeysAndValues.put(inputId, data.getKeyValues());
myInMemoryKeysAndValues.put(inputId, data);
}
} else {
super.updateForwardIndex(inputId, data);
super.updateForwardIndex(inputId, data, forwardIndexData);
}
}
@@ -248,7 +248,7 @@ public class VfsAwareMapReduceIndex<Key, Value, Input> extends MapReduceIndex<Ke
}
if (getForwardIndexAccessor() instanceof AbstractMapForwardIndexAccessor) {
ByteArraySequence serializedInputData = getForwardIndexMap().get(fileId);
AbstractMapForwardIndexAccessor<Key, Value, ?> forwardIndexAccessor = (AbstractMapForwardIndexAccessor<Key, Value, ?>)getForwardIndexAccessor();
AbstractMapForwardIndexAccessor<Key, Value, ?, Input> forwardIndexAccessor = (AbstractMapForwardIndexAccessor<Key, Value, ?, Input>)getForwardIndexAccessor();
return forwardIndexAccessor.convertToInputDataMap(serializedInputData);
}
// in future we will get rid of forward index for SingleEntryFileBasedIndexExtension
@@ -319,7 +319,7 @@ public class VfsAwareMapReduceIndex<Key, Value, Input> extends MapReduceIndex<Ke
}
@Nullable
private static <Key, Value> ForwardIndexAccessor<Key, Value> getForwardIndexAccessor(@NotNull IndexExtension<Key, Value, ?> indexExtension) {
private static <Key, Value, Input> ForwardIndexAccessor<Key, Value, ?, Input> getForwardIndexAccessor(@NotNull IndexExtension<Key, Value, Input> indexExtension) {
if (!shouldCreateForwardIndex(indexExtension)) return null;
return new MapForwardIndexAccessor<>(new InputMapExternalizer<>(indexExtension));
}
@@ -1,51 +0,0 @@
/*
* Copyright 2000-2009 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.ide.ui.search;
import com.intellij.openapi.options.Configurable;
import java.util.Set;
import java.util.LinkedHashSet;
public final class ConfigurableHit {
private final Set<Configurable> myNameHits = new LinkedHashSet<>();
private final Set<Configurable> myContentHits = new LinkedHashSet<>();
private final Set<Configurable> myNameFullHit = new LinkedHashSet<>();
ConfigurableHit() {
}
public Set<Configurable> getNameHits() {
return myNameHits;
}
public Set<Configurable> getNameFullHits() {
return myNameFullHit;
}
public Set<Configurable> getContentHits() {
return myContentHits;
}
public Set<Configurable> getAll() {
final LinkedHashSet<Configurable> all = new LinkedHashSet<>(myNameHits.size() + myContentHits.size());
all.addAll(myNameHits);
all.addAll(myContentHits);
return all;
}
}
@@ -0,0 +1,15 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.ui.search
import com.intellij.openapi.options.Configurable
import java.util.*
data class ConfigurableHit(val contentHits: Set<Configurable>, val nameHits: Set<Configurable>, val nameFullHits: Set<Configurable>) {
val all: Set<Configurable>
get() {
val all = LinkedHashSet<Configurable>(nameHits.size + contentHits.size)
all.addAll(nameHits)
all.addAll(contentHits)
return all
}
}
@@ -1,5 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.ui.search;
import com.intellij.openapi.components.ServiceManager;
@@ -11,22 +10,22 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.DocumentEvent;
import java.util.Map;
import java.util.List;
import java.util.Set;
public abstract class SearchableOptionsRegistrar{
public static final String SEARCHABLE_OPTIONS_XML = "searchableOptions.xml";
public static SearchableOptionsRegistrar getInstance(){
public static SearchableOptionsRegistrar getInstance() {
return ServiceManager.getService(SearchableOptionsRegistrar.class);
}
@NotNull
public abstract ConfigurableHit getConfigurables(final ConfigurableGroup[] groups,
final DocumentEvent.EventType type,
final Set<? extends Configurable> configurables,
final String option,
final Project project);
public abstract ConfigurableHit getConfigurables(@NotNull List<ConfigurableGroup> groups,
final DocumentEvent.EventType type,
@Nullable Set<? extends Configurable> configurables,
@NotNull String option,
@Nullable Project project);
@Nullable
public abstract String getInnerPath(SearchableConfigurable configurable, String option);
@@ -39,11 +38,7 @@ public abstract class SearchableOptionsRegistrar{
public abstract Set<String> replaceSynonyms(Set<String> options, SearchableConfigurable configurable);
public abstract Map<String, Set<String>> findPossibleExtension(@NotNull String prefix, final Project project);
public abstract Set<String> getProcessedWordsWithoutStemming(@NotNull String text);
public abstract Set<String> getProcessedWords(@NotNull String text);
}
@@ -22,7 +22,6 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.ui.ComponentTreeWatcher;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.JBTreeTraverser;
import com.intellij.util.ui.DialogUtil;
import com.intellij.util.ui.UIUtil;
import org.intellij.lang.annotations.MagicConstant;
@@ -183,9 +182,7 @@ public class MnemonicHelper extends ComponentTreeWatcher {
private static class MnemonicFixer implements ContainerListener {
void addTo(Component component) {
JBTreeTraverser<Component> traverser = UIUtil.uiTraverser(component)
.expandAndFilter(o -> !(o instanceof CellRendererPane));
for (Component c : traverser) {
for (Component c : UIUtil.uiTraverser(component)) {
if (c instanceof Container) ((Container)c).addContainerListener(this);
if (c instanceof ActionButtonComponent) fixMacMnemonicKeyStroke((JComponent)c, null);
MnemonicWrapper.getWrapper(c);
@@ -193,9 +190,7 @@ public class MnemonicHelper extends ComponentTreeWatcher {
}
void removeFrom(Component component) {
JBTreeTraverser<Component> traverser = UIUtil.uiTraverser(component)
.expandAndFilter(o -> !(o instanceof CellRendererPane));
for (Container c : traverser.traverse().filter(Container.class)) {
for (Container c : UIUtil.uiTraverser(component).filter(Container.class)) {
c.removeContainerListener(this);
}
}
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.options;
import com.intellij.openapi.components.ServiceManager;
@@ -23,7 +23,7 @@ public abstract class ShowSettingsUtil {
public abstract void showSettingsDialog(@Nullable Project project, @NotNull String nameToSelect);
public abstract void showSettingsDialog(@NotNull final Project project, final Configurable toSelect);
public abstract void showSettingsDialog(@NotNull Project project, @Nullable Configurable toSelect);
public abstract <T extends Configurable> void showSettingsDialog(@Nullable Project project,
@NotNull Class<T> configurableClass,
@@ -47,13 +47,6 @@ public abstract class ShowSettingsUtil {
public abstract boolean editConfigurable(Component parent, String dimensionServiceKey, Configurable configurable);
/**
* @deprecated create a new instance of configurable instead
* to remove in IDEA 15
*/
@Deprecated
public abstract <T extends Configurable> T findProjectConfigurable(Project project, Class<T> confClass);
public static String getSettingsMenuName() {
return SystemInfo.isMac ? "Preferences" : "Settings";
}
@@ -1,25 +1,14 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.ui;
public interface TestDialog {
TestDialog DEFAULT = new TestDialog() {
@Override
public int show(String message) {
throw new RuntimeException(message);
}
};
TestDialog OK = new TestDialog() {
@Override
public int show(String message) {
return 0;
}
};
TestDialog NO = new TestDialog() {
@Override
public int show(String message) {
return Messages.NO;
}
};
import org.jetbrains.annotations.NotNull;
int show(String message);
public interface TestDialog {
TestDialog DEFAULT = message -> {
throw new RuntimeException(message);
};
TestDialog OK = __ -> Messages.OK;
TestDialog NO = __ -> Messages.NO;
int show(@NotNull String message);
}
@@ -1,24 +1,13 @@
/*
* 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.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ui.speedSearch;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.concurrency.Promise;
import org.jetbrains.concurrency.Promises;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
@@ -27,7 +16,8 @@ public interface ElementFilter<T> {
boolean shouldBeShowing(T value);
interface Active<T> extends ElementFilter<T> {
ActionCallback fireUpdate(@Nullable final T preferredSelection, final boolean adjustSelection, final boolean now);
@NotNull
Promise<?> fireUpdate(@Nullable final T preferredSelection, final boolean adjustSelection, final boolean now);
void addListener(Listener<T> listener, Disposable parent);
@@ -35,14 +25,9 @@ public interface ElementFilter<T> {
Set<Listener<T>> myListeners = new CopyOnWriteArraySet<>();
@Override
public ActionCallback fireUpdate(@Nullable final T preferredSelection, final boolean adjustSelection, final boolean now) {
final ActionCallback result = new ActionCallback(myListeners.size());
for (final Listener<T> myListener : myListeners) {
myListener.update(preferredSelection, adjustSelection, now).doWhenProcessed(result.createSetDoneRunnable());
}
return result;
@NotNull
public Promise<?> fireUpdate(@Nullable T preferredSelection, boolean adjustSelection, boolean now) {
return Promises.all(ContainerUtil.map(myListeners, listener -> listener.update(preferredSelection, adjustSelection, now)));
}
@Override
@@ -59,6 +44,7 @@ public interface ElementFilter<T> {
}
interface Listener<T> {
ActionCallback update(@Nullable final T preferredSelection, final boolean adjustSelection, final boolean now);
@NotNull
Promise<Void> update(@Nullable final T preferredSelection, final boolean adjustSelection, final boolean now);
}
}
@@ -182,14 +182,20 @@ public class TabLabel extends JPanel implements Accessible {
@Override
public Insets getInsets() {
Insets insets = super.getInsets();
boolean hasCloseButtonOnTheLeft = false;
if (myTabs.isEditorTabs() && UISettings.getShadowInstance().getShowCloseButton() && hasIcons()) {
if (UISettings.getShadowInstance().getCloseTabButtonOnTheRight()) {
insets.right -= JBUI.scale(4);
}
else {
hasCloseButtonOnTheLeft = true;
insets.left -= JBUI.scale(4);
}
}
// We reserve extra space inside file icon for (*) marker but mostly this space looks like wasted one
if (myTabs.isEditorTabs() && UISettings.getShadowInstance().getMarkModifiedTabsWithAsterisk() && !hasCloseButtonOnTheLeft) {
insets.left -= JBUI.scale(7);
}
return insets;
}

Some files were not shown because too many files have changed in this diff Show More