From b9507243ef5500349be9e2116bbfbd250959fd33 Mon Sep 17 00:00:00 2001 From: Liana Bakradze Date: Wed, 22 Oct 2014 15:15:14 +0400 Subject: [PATCH 01/26] EDU-83 Add shortcut text to the next/prev/check button tooltip --- python/edu/learn-python/resources/META-INF/plugin.xml | 2 ++ .../jetbrains/python/edu/StudyInstructionPainter.java | 5 ++++- .../com/jetbrains/python/edu/StudyTaskManager.java | 8 +++++--- .../python/edu/actions/StudyCheckAction.java | 2 ++ .../python/edu/actions/StudyNextStudyTaskAction.java | 3 +++ .../python/edu/actions/StudyNextWindowAction.java | 2 +- .../python/edu/actions/StudyPrevWindowAction.java | 2 +- .../edu/actions/StudyPreviousStudyTaskAction.java | 2 ++ .../edu/actions/StudyRefreshTaskFileAction.java | 2 ++ .../com/jetbrains/python/edu/editor/StudyEditor.java | 11 +++++------ 10 files changed, 27 insertions(+), 12 deletions(-) diff --git a/python/edu/learn-python/resources/META-INF/plugin.xml b/python/edu/learn-python/resources/META-INF/plugin.xml index 59457f3a1a95..620796a8435c 100644 --- a/python/edu/learn-python/resources/META-INF/plugin.xml +++ b/python/edu/learn-python/resources/META-INF/plugin.xml @@ -54,6 +54,8 @@ description="Refresh current task"/> + diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyInstructionPainter.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyInstructionPainter.java index 96a44b2ee66a..4fa323172bcc 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyInstructionPainter.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyInstructionPainter.java @@ -28,7 +28,10 @@ public class StudyInstructionPainter extends EditorEmptyTextPainter { painter.appendLine("PyCharm Educational Edition").underlined(new JBColor(Gray._150, Gray._180)); painter.appendLine("Navigate to the next task window with Ctrl + Enter").smaller().withBullet(); - painter.appendLine("Navigate between task windows with Ctrl + < and Ctrl + >").smaller().withBullet(); + painter.appendLine("Navigate between task windows with Ctrl + Shift + < and Ctrl + Shift + >").smaller().withBullet(); + painter.appendLine("Navigate between tasks with Ctrl + < and Ctrl + >").smaller().withBullet(); + painter.appendLine("Reset current task file with Ctrl + Shift + X").smaller().withBullet(); + painter.appendLine("Check task with Alt + Ctrl + Enter").smaller().withBullet(); painter.appendLine("Get hint for the task window using Ctrl + 7").smaller().withBullet(); painter.appendLine("To see your progress open the 'Course Description' panel").smaller().withBullet(); painter.draw(g, new PairFunction>() { diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java index 3013fbcb05d3..9b935504bd5c 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTaskManager.java @@ -20,9 +20,7 @@ import com.intellij.openapi.vfs.VirtualFileEvent; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.wm.*; import com.intellij.util.xmlb.XmlSerializer; -import com.jetbrains.python.edu.actions.StudyNextWindowAction; -import com.jetbrains.python.edu.actions.StudyPrevWindowAction; -import com.jetbrains.python.edu.actions.StudyShowHintAction; +import com.jetbrains.python.edu.actions.*; import com.jetbrains.python.edu.course.Course; import com.jetbrains.python.edu.course.Lesson; import com.jetbrains.python.edu.course.Task; @@ -155,6 +153,10 @@ public class StudyTaskManager implements ProjectComponent, PersistentStateCompon addShortcut(StudyPrevWindowAction.SHORTCUT, StudyPrevWindowAction.ACTION_ID); addShortcut(StudyShowHintAction.SHORTCUT, StudyShowHintAction.ACTION_ID); addShortcut(StudyNextWindowAction.SHORTCUT2, StudyNextWindowAction.ACTION_ID); + addShortcut(StudyCheckAction.SHORTCUT, StudyCheckAction.ACTION_ID); + addShortcut(StudyNextStudyTaskAction.SHORTCUT, StudyNextStudyTaskAction.ACTION_ID); + addShortcut(StudyPreviousStudyTaskAction.SHORTCUT, StudyPreviousStudyTaskAction.ACTION_ID); + addShortcut(StudyRefreshTaskFileAction.SHORTCUT, StudyRefreshTaskFileAction.ACTION_ID); } } }); diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java index 9741a240b0ec..b5f4c003ffe8 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java @@ -41,6 +41,8 @@ public class StudyCheckAction extends DumbAwareAction { private static final Logger LOG = Logger.getInstance(StudyCheckAction.class.getName()); private static final String ANSWERS_POSTFIX = "_answers.py"; + public static final String ACTION_ID = "CheckAction"; + public static final String SHORTCUT = "ctrl alt pressed ENTER"; private static void flushWindows(@NotNull final Task task, @NotNull final VirtualFile taskDir) { diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextStudyTaskAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextStudyTaskAction.java index 3c971c3fe15e..27edf22529cd 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextStudyTaskAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextStudyTaskAction.java @@ -8,6 +8,9 @@ import javax.swing.*; public class StudyNextStudyTaskAction extends StudyTaskNavigationAction { + public static final String ACTION_ID = "NextTaskAction"; + public static final String SHORTCUT = "ctrl pressed PERIOD"; + @Override protected JButton getButton(@NotNull final StudyEditor selectedStudyEditor) { return selectedStudyEditor.getNextTaskButton(); diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextWindowAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextWindowAction.java index fcf9ef40c7d4..16036a7ba91b 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextWindowAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNextWindowAction.java @@ -12,7 +12,7 @@ import java.util.List; */ public class StudyNextWindowAction extends StudyWindowNavigationAction { public static final String ACTION_ID = "NextWindow"; - public static final String SHORTCUT = "ctrl pressed PERIOD"; + public static final String SHORTCUT = "ctrl shift pressed PERIOD"; public static final String SHORTCUT2 = "ctrl pressed ENTER"; public StudyNextWindowAction() { diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPrevWindowAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPrevWindowAction.java index 347456189a00..1e602bd059ff 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPrevWindowAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPrevWindowAction.java @@ -14,7 +14,7 @@ import java.util.List; */ public class StudyPrevWindowAction extends StudyWindowNavigationAction { public static final String ACTION_ID = "PrevWindowAction"; - public static final String SHORTCUT = "ctrl pressed COMMA"; + public static final String SHORTCUT = "ctrl shift pressed COMMA"; public StudyPrevWindowAction() { super("PrevWindowAction", "Select previous window", StudyIcons.Prev); diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPreviousStudyTaskAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPreviousStudyTaskAction.java index f6da6a067894..02cc36355834 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPreviousStudyTaskAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyPreviousStudyTaskAction.java @@ -9,6 +9,8 @@ import javax.swing.*; public class StudyPreviousStudyTaskAction extends StudyTaskNavigationAction { + public static final String ACTION_ID = "PreviousTaskAction"; + public static final String SHORTCUT = "ctrl pressed COMMA"; @Override protected JButton getButton(@NotNull final StudyEditor selectedStudyEditor) { return selectedStudyEditor.getPrevTaskButton(); diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java index b1ff29b58270..1a15afdf7013 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java @@ -28,6 +28,8 @@ import java.io.*; public class StudyRefreshTaskFileAction extends DumbAwareAction { private static final Logger LOG = Logger.getInstance(StudyRefreshTaskFileAction.class.getName()); + public static final String ACTION_ID = "RefreshTaskAction"; + public static final String SHORTCUT = "ctrl shift pressed X"; public static void refresh(final Project project) { ApplicationManager.getApplication().invokeLater(new Runnable() { diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java b/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java index a85df6c4cf14..ec661f8f0b88 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java @@ -66,7 +66,6 @@ public class StudyEditor implements TextEditor { private JButton myRefreshButton; private static final Map myDocumentListeners = new HashMap(); private final Project myProject; - private JButton myShowHintButton; public JButton getCheckButton() { return myCheckButton; @@ -193,11 +192,11 @@ public class StudyEditor implements TextEditor { } private void initializeButtons(@NotNull final JPanel taskActionsPanel, @NotNull final TaskFile taskFile) { - myCheckButton = addButton(taskActionsPanel, "Check task", StudyIcons.Resolve); - myPrevTaskButton = addButton(taskActionsPanel, "Prev Task", StudyIcons.Prev); - myNextTaskButton = addButton(taskActionsPanel, "Next Task", AllIcons.Actions.Forward); - myRefreshButton = addButton(taskActionsPanel, "Start task again", AllIcons.Actions.Refresh); - myShowHintButton = addButton(taskActionsPanel, "Show hint", StudyIcons.ShowHint); + myCheckButton = addButton(taskActionsPanel, "Check task (Ctrl + Alt + Enter)", StudyIcons.Resolve); + myPrevTaskButton = addButton(taskActionsPanel, "Previous task (Ctrl + <)", StudyIcons.Prev); + myNextTaskButton = addButton(taskActionsPanel, "Next task (Ctrl + >)", AllIcons.Actions.Forward); + myRefreshButton = addButton(taskActionsPanel, "Reset task file (Ctrl + Shift + X)", AllIcons.Actions.Refresh); + JButton myShowHintButton = addButton(taskActionsPanel, "Show hint for task window (Ctrl + 7)", StudyIcons.ShowHint); if (!taskFile.getTask().getUserTests().isEmpty()) { JButton runButton = addButton(taskActionsPanel, "Run", AllIcons.General.Run); runButton.addActionListener(new ActionListener() { From 3b281d3e7e5681bb3d1710df798ff37c33bcc0fe Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Wed, 22 Oct 2014 15:39:46 +0400 Subject: [PATCH 02/26] screen mode -> view mode --- .../src/messages/ActionsBundle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index f80f272c8933..81e770d767b3 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -1009,8 +1009,8 @@ action.ChangeKeymap.text=Keymap action.ChangeKeymap.description=Change current keymap action.ChangeLaf.text=Look and Feel action.ChangeLaf.description=Change current Look\\&Feel -action.ChangeView.text=Screen Mode -action.ChangeView.description=Change screen mode +action.ChangeView.text=View Mode +action.ChangeView.description=Change view mode action.ChangeInspectionProfile.text=Switch Error Highlighting action.ChangeInspectionProfile.description=Change current editor inspection profile action.ChangeCustomizationSchema.text=Switch Customization Scheme From 9821cbab0304ac6a0630f8248bab5dde54cfbab4 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 22 Oct 2014 13:41:06 +0200 Subject: [PATCH 03/26] dfa live var analysis should honor variables read in closures (IDEA-131719) --- .../dataFlow/DataFlowRunner.java | 23 +---- .../codeInspection/dataFlow/DfaUtil.java | 24 ++++- .../dataFlow/LiveVariablesAnalyzer.java | 95 +++++++++++++------ .../DontFlushVariablesUsedInClosures.java | 19 ++++ .../DataFlowInspectionTest.java | 1 + 5 files changed, 111 insertions(+), 51 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/DontFlushVariablesUsedInClosures.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java index 6db340c5ea10..6eeb6414ff22 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowRunner.java @@ -222,24 +222,11 @@ public class DataFlowRunner { protected DfaInstructionState[] acceptInstruction(InstructionVisitor visitor, DfaInstructionState instructionState) { Instruction instruction = instructionState.getInstruction(); - if (instruction instanceof MethodCallInstruction) { - PsiCallExpression anchor = ((MethodCallInstruction)instruction).getCallExpression(); - if (anchor instanceof PsiNewExpression) { - PsiAnonymousClass anonymousClass = ((PsiNewExpression)anchor).getAnonymousClass(); - if (anonymousClass != null) { - registerNestedClosures(instructionState, anonymousClass); - } - } - } - else if (instruction instanceof LambdaInstruction) { - PsiLambdaExpression lambdaExpression = ((LambdaInstruction)instruction).getLambdaExpression(); - registerNestedClosures(instructionState, lambdaExpression); - } - else if (instruction instanceof EmptyInstruction) { - PsiElement anchor = ((EmptyInstruction)instruction).getAnchor(); - if (anchor instanceof PsiClass) { - registerNestedClosures(instructionState, (PsiClass)anchor); - } + PsiElement closure = DfaUtil.getClosureInside(instruction); + if (closure instanceof PsiClass) { + registerNestedClosures(instructionState, (PsiClass)closure); + } else if (closure instanceof PsiLambdaExpression) { + registerNestedClosures(instructionState, (PsiLambdaExpression)closure); } return instruction.accept(this, instructionState.getMemoryState(), visitor); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java index d147c270c1c5..6bb70010c9ca 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java @@ -15,9 +15,7 @@ */ package com.intellij.codeInspection.dataFlow; -import com.intellij.codeInspection.dataFlow.instructions.AssignInstruction; -import com.intellij.codeInspection.dataFlow.instructions.Instruction; -import com.intellij.codeInspection.dataFlow.instructions.PushInstruction; +import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; import com.intellij.openapi.util.MultiValuesMap; @@ -113,6 +111,26 @@ public class DfaUtil { return Collections.emptyList(); } + @Nullable + static PsiElement getClosureInside(Instruction instruction) { + if (instruction instanceof MethodCallInstruction) { + PsiCallExpression anchor = ((MethodCallInstruction)instruction).getCallExpression(); + if (anchor instanceof PsiNewExpression) { + return ((PsiNewExpression)anchor).getAnonymousClass(); + } + } + else if (instruction instanceof LambdaInstruction) { + return ((LambdaInstruction)instruction).getLambdaExpression(); + } + else if (instruction instanceof EmptyInstruction) { + PsiElement anchor = ((EmptyInstruction)instruction).getAnchor(); + if (anchor instanceof PsiClass) { + return anchor; + } + } + return null; + } + private static class ValuableInstructionVisitor extends StandardInstructionVisitor { final Map myResults = ContainerUtil.newHashMap(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java index 55709d71ca49..937caa84e24d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java @@ -21,10 +21,11 @@ import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiRecursiveElementWalkingVisitor; +import com.intellij.psi.PsiReferenceExpression; import com.intellij.util.PairFunction; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.FilteringIterator; -import com.intellij.util.containers.MultiMap; +import com.intellij.util.containers.*; import com.intellij.util.containers.Queue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,6 +40,26 @@ public class LiveVariablesAnalyzer { private final Instruction[] myInstructions; private final MultiMap myForwardMap; private final MultiMap myBackwardMap; + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") private final FactoryMap> myClosureReads = new FactoryMap>() { + @Nullable + @Override + protected List create(PsiElement closure) { + final Set result = ContainerUtil.newLinkedHashSet(); + closure.accept(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (element instanceof PsiReferenceExpression) { + DfaValue value = myFactory.createValue((PsiReferenceExpression)element); + if (value instanceof DfaVariableValue) { + result.add((DfaVariableValue)value); + } + } + super.visitElement(element); + } + }); + return ContainerUtil.newArrayList(result); + } + }; public LiveVariablesAnalyzer(ControlFlow flow, DfaValueFactory factory) { myFactory = factory; @@ -96,12 +117,36 @@ public class LiveVariablesAnalyzer { return result; } + @Nullable + private static DfaVariableValue getWrittenVariable(Instruction instruction) { + if (instruction instanceof AssignInstruction) { + DfaValue value = ((AssignInstruction)instruction).getAssignedValue(); + return value instanceof DfaVariableValue ? (DfaVariableValue)value : null; + } + if (instruction instanceof FlushVariableInstruction) return ((FlushVariableInstruction)instruction).getVariable(); + return null; + } + + @NotNull + private List getReadVariables(Instruction instruction) { + if (instruction instanceof PushInstruction && !((PushInstruction)instruction).isReferenceWrite()) { + DfaValue value = ((PushInstruction)instruction).getValue(); + if (value instanceof DfaVariableValue) { + return Collections.singletonList((DfaVariableValue)value); + } + } else { + PsiElement closure = DfaUtil.getClosureInside(instruction); + if (closure != null) { + return myClosureReads.get(closure); + } + } + return Collections.emptyList(); + } + private boolean isInterestingInstruction(Instruction instruction) { if (instruction == myInstructions[0]) return true; - if (instruction instanceof PushInstruction) return ((PushInstruction)instruction).getValue() instanceof DfaVariableValue; - if (instruction instanceof AssignInstruction) return ((AssignInstruction)instruction).getAssignedValue() != null; + if (!getReadVariables(instruction).isEmpty() || getWrittenVariable(instruction) != null) return true; return instruction instanceof FinishElementInstruction || - instruction instanceof FlushVariableInstruction || instruction instanceof GotoInstruction || instruction instanceof ConditionalGotoInstruction || instruction instanceof ReturnInstruction; @@ -124,34 +169,24 @@ public class LiveVariablesAnalyzer { } } - if (instruction instanceof AssignInstruction) { - DfaValue value = ((AssignInstruction)instruction).getAssignedValue(); - if (value instanceof DfaVariableValue) { - liveVars = (BitSet)liveVars.clone(); - liveVars.clear(value.getID()); - for (DfaVariableValue var : myFactory.getVarFactory().getAllQualifiedBy((DfaVariableValue)value)) { - liveVars.clear(var.getID()); - } + DfaVariableValue written = getWrittenVariable(instruction); + if (written != null) { + liveVars = (BitSet)liveVars.clone(); + liveVars.clear(written.getID()); + for (DfaVariableValue var : myFactory.getVarFactory().getAllQualifiedBy(written)) { + liveVars.clear(var.getID()); } - } - - if (instruction instanceof PushInstruction) { - DfaValue value = ((PushInstruction)instruction).getValue(); - if (value instanceof DfaVariableValue) { - if (!((PushInstruction)instruction).isReferenceWrite() && !liveVars.get(value.getID())) { - liveVars = (BitSet)liveVars.clone(); + } else { + boolean cloned = false; + for (DfaVariableValue value : getReadVariables(instruction)) { + if (!liveVars.get(value.getID())) { + if (!cloned) { + liveVars = (BitSet)liveVars.clone(); + cloned = true; + } liveVars.set(value.getID()); } } - } else if (instruction instanceof FlushVariableInstruction) { - DfaVariableValue variable = ((FlushVariableInstruction)instruction).getVariable(); - if (variable != null) { - liveVars = (BitSet)liveVars.clone(); - liveVars.clear(variable.getID()); - for (DfaVariableValue var : myFactory.getVarFactory().getAllQualifiedBy(variable)) { - liveVars.clear(var.getID()); - } - } } return liveVars; diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/DontFlushVariablesUsedInClosures.java b/java/java-tests/testData/inspection/dataFlow/fixture/DontFlushVariablesUsedInClosures.java new file mode 100644 index 000000000000..bc2ed3cfe2f1 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/DontFlushVariablesUsedInClosures.java @@ -0,0 +1,19 @@ +import org.jetbrains.annotations.Nullable; + +class Foo { + + void foo(final @Nullable String s, String s2) { + if (s2 == null) return; + if (s == null) return; + + System.out.println(s2); + + new Runnable() { + @Override + public void run() { + s.hashCode(); + } + }.run(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index dba230fbed32..cc86a456004f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -242,6 +242,7 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { public void testManyContinuesNotComplex() { doTest(); } public void testFinallyNotComplex() { doTest(); } public void testFlushFurtherUnusedVariables() { doTest(); } + public void testDontFlushVariablesUsedInClosures() { doTest(); } public void testVariablesDiverge() { doTest(); } public void testMergeByNullability() { doTest(); } From 195648e0e4eb5ba96a4d1434d42a501a3bea51b4 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 22 Oct 2014 13:54:50 +0200 Subject: [PATCH 04/26] an ability to turn dfa live var analysis off in registry --- .../codeInspection/dataFlow/ControlFlowAnalyzer.java | 5 ++++- platform/util/resources/misc/registry.properties | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 496bd289247e..3face7908ec1 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -20,6 +20,7 @@ import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; @@ -100,7 +101,9 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { addInstruction(new ReturnInstruction(false, null)); - new LiveVariablesAnalyzer(myCurrentFlow, myFactory).flushDeadVariablesOnStatementFinish(); + if (Registry.is("idea.dfa.live.variables.analysis")) { + new LiveVariablesAnalyzer(myCurrentFlow, myFactory).flushDeadVariablesOnStatementFinish(); + } return myCurrentFlow; } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index bef1c10517d7..5a14ade2ba5c 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -281,6 +281,9 @@ ide.dfa.time.limit.online.description=Time limit (in milliseconds) that is allow ide.dfa.time.limit.offline=5000 ide.dfa.time.limit.offline.description=Time limit (in milliseconds) that is allowed to analyze data flow for one method in Analyze | Inspect Code... +idea.dfa.live.variables.analysis=true +idea.dfa.live.variables.analysis.description=Whether to flush dead variables when they're not needed when performing data flow analysis + ide.ignore.call.result.inspection.honor.inferred.pure=false ide.ignore.call.result.inspection.honor.inferred.pure.description=Whether inferred @Contract(pure=true) annotations should be taken into account in ''Result of method call ignored'' inspection From 4d4559cb50c70977479639fb319e62cabbe2393a Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 22 Oct 2014 16:05:46 +0400 Subject: [PATCH 05/26] support breakpoints in decompiled code --- .../engine/CompoundPositionManager.java | 21 +++++++++++++++++++ .../debugger/engine/PositionManagerImpl.java | 2 +- .../JavaLineBreakpointTypeBase.java | 8 +++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java b/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java index 5ec84a8429f5..73d6f8bdb62b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/CompoundPositionManager.java @@ -22,6 +22,7 @@ import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.jdi.StackFrameProxyImpl; import com.intellij.debugger.requests.ClassPrepareRequestor; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ThreeState; import com.intellij.xdebugger.frame.XStackFrame; import com.sun.jdi.InternalException; @@ -101,9 +102,29 @@ public class CompoundPositionManager extends PositionManagerEx { return Collections.emptyList(); } + private static int mapToOriginalLine(int line, int[] mapping) { + for (int i = 0; i < mapping.length; i += 2) { + if (mapping[i + 1] == line) { + return mapping[i]; + } + } + return -1; + } + @Override @NotNull public List locationsOfLine(@NotNull ReferenceType type, @NotNull SourcePosition position) { + VirtualFile file = position.getFile().getVirtualFile(); + if (file != null) { + int[] data = file.getUserData(LINE_NUMBERS_MAPPING_KEY); + if (data != null) { + int line = mapToOriginalLine(position.getLine() + 1, data); + if (line > -1) { + position = SourcePosition.createFromLine(position.getFile(), line - 1); + } + } + } + for (PositionManager positionManager : myPositionManagers) { try { return positionManager.locationsOfLine(type, position); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index 44337a6f1ee3..c58e7770d449 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -140,7 +140,7 @@ public class PositionManagerImpl implements PositionManager { lineNumber = -1; } - if (psiFile instanceof PsiCompiledElement && lineNumber > -1) { + if (lineNumber > -1) { VirtualFile file = psiFile.getVirtualFile(); if (file != null) { int[] data = file.getUserData(LINE_NUMBERS_MAPPING_KEY); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java index 7427f91df500..8f092e26975b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/JavaLineBreakpointTypeBase.java @@ -15,6 +15,7 @@ */ package com.intellij.debugger.ui.breakpoints; +import com.intellij.debugger.PositionManager; import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -81,8 +82,8 @@ public abstract class JavaLineBreakpointTypeBase

Date: Wed, 22 Oct 2014 16:07:36 +0400 Subject: [PATCH 06/26] [log] more debug info for "no references pointing to head" error --- .../vcs/log/ui/tables/GraphTableModel.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java index 47b9375a7369..5abaaf2da696 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java @@ -8,7 +8,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Function; -import com.intellij.util.NotNullFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.DateFormatUtil; import com.intellij.vcs.log.*; @@ -75,24 +74,32 @@ public class GraphTableModel extends AbstractTableModel { List> commits = myDataPack.getPermanentGraph().getAllCommits(); for (int i = 0; i < 100 && i < commits.size(); i++) { GraphCommit commit = commits.get(i); - sb.append(myDataHolder.getHash(commit.getId()) + "\n"); + sb.append(String.format("%s -> %s\n", myDataHolder.getHash(commit.getId()).toShortString(), getParents(commit))); } sb.append("\nALL REFS:\n"); - printRefs(sb, myDataHolder.getHashMap().asIndexGetter(), myDataPack.getRefsModel().getAllRefsByRoot()); + printRefs(sb, myDataPack.getRefsModel().getAllRefsByRoot()); return sb.toString(); } - private static void printRefs(@NotNull StringBuilder sb, - @NotNull final NotNullFunction indexGetter, - @NotNull Map> refs) { + @NotNull + private String getParents(@NotNull GraphCommit commit) { + return StringUtil.join(commit.getParents(), new Function() { + @Override + public String fun(Integer integer) { + return myDataHolder.getHash(integer).toShortString(); + } + }, ", "); + } + + private static void printRefs(@NotNull StringBuilder sb, @NotNull Map> refs) { for (Map.Entry> entry : refs.entrySet()) { - sb.append(entry.getKey().getName() + ":\n"); + sb.append("\n\n" + entry.getKey().getName() + ":\n"); sb.append(StringUtil.join(entry.getValue(), new Function() { @Override public String fun(@NotNull VcsRef ref) { - return ref.getName() + "(" + indexGetter.fun(ref.getCommitHash()) + ")"; + return ref.getName() + " : " + ref.getCommitHash().toShortString(); } - }, ",")); + }, "\n")); } } From 9f3baaa1544b3bbf7870f51cf7b703837411cb6f Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Wed, 22 Oct 2014 14:09:21 +0200 Subject: [PATCH 07/26] test for IDEA-128919 --- .../testSrc/com/intellij/index/IndexTest.java | 159 ++++++++++++++++-- 1 file changed, 146 insertions(+), 13 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.java b/java/java-tests/testSrc/com/intellij/index/IndexTest.java index 4fcb40296a48..f561fef91882 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.java +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.java @@ -15,19 +15,26 @@ */ package com.intellij.index; +import com.intellij.codeHighlighting.BackgroundEditorHighlighter; +import com.intellij.codeInsight.CodeInsightTestCase; +import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.*; import com.intellij.openapi.fileTypes.PlainTextFileType; import com.intellij.openapi.util.Factory; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry; +import com.intellij.pom.Navigatable; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiSearchHelper; -import com.intellij.testFramework.IdeaTestCase; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.SkipSlowTestLocally; @@ -35,7 +42,10 @@ import com.intellij.util.indexing.MapIndexStorage; import com.intellij.util.indexing.StorageException; import com.intellij.util.io.*; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import javax.swing.*; +import java.beans.PropertyChangeListener; import java.io.DataInput; import java.io.DataOutput; import java.io.File; @@ -47,7 +57,7 @@ import java.util.*; * Date: Dec 12, 2007 */ @SkipSlowTestLocally -public class IndexTest extends IdeaTestCase { +public class IndexTest extends CodeInsightTestCase { public void testUpdate() throws StorageException, IOException { final File storageFile = FileUtil.createTempFile("indextest", "storage"); @@ -208,8 +218,7 @@ public class IndexTest extends IdeaTestCase { VfsUtil.saveText(vFile, "class Foo {}"); final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); - final JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject()); - assertNotNull(facade.findClass("Foo", scope)); + assertNotNull(myJavaFacade.findClass("Foo", scope)); WriteCommandAction.runWriteCommandAction(null, new Runnable() { @Override public void run() { @@ -218,20 +227,20 @@ public class IndexTest extends IdeaTestCase { Document document = FileDocumentManager.getInstance().getDocument(vFile); document.deleteString(0, document.getTextLength()); - assertNotNull(facade.findClass("Foo", scope)); + assertNotNull(myJavaFacade.findClass("Foo", scope)); psiFile = null; PlatformTestUtil.tryGcSoftlyReachableObjects(); assertNull(((PsiManagerEx)PsiManager.getInstance(getProject())).getFileManager().getCachedPsiFile(vFile)); - PsiClass foo = facade.findClass("Foo", scope); + PsiClass foo = myJavaFacade.findClass("Foo", scope); assertNotNull(foo); assertTrue(foo.isValid()); assertEquals("class Foo {}", foo.getText()); assertTrue(foo.isValid()); PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNull(facade.findClass("Foo", scope)); + assertNull(myJavaFacade.findClass("Foo", scope)); } }); } @@ -244,8 +253,7 @@ public class IndexTest extends IdeaTestCase { VfsUtil.saveText(vFile, ""); final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); - final JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject()); - assertNull(facade.findClass("Foo", scope)); + assertNull(myJavaFacade.findClass("Foo", scope)); WriteCommandAction.runWriteCommandAction(null, new Runnable() { @Override public void run() { @@ -259,11 +267,11 @@ public class IndexTest extends IdeaTestCase { FileDocumentManager.getInstance().saveDocument(document); assertTrue(count == PsiManager.getInstance(myProject).getModificationTracker().getModificationCount()); - assertNull(facade.findClass("Foo", scope)); + assertNull(myJavaFacade.findClass("Foo", scope)); PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - assertNotNull(facade.findClass("Foo", scope)); - assertNotNull(facade.findClass("Foo", scope).getText()); + assertNotNull(myJavaFacade.findClass("Foo", scope)); + assertNotNull(myJavaFacade.findClass("Foo", scope).getText()); // if Foo exists now, mod count should be different assertTrue(count != PsiManager.getInstance(myProject).getModificationTracker().getModificationCount()); } @@ -308,4 +316,129 @@ public class IndexTest extends IdeaTestCase { }); } + public void testUndoToFileContentForUnsavedCommittedDocument() throws IOException { + VirtualFile dir = getVirtualFile(createTempDirectory()); + PsiTestUtil.addSourceContentToRoots(myModule, dir); + + final VirtualFile vFile = createChildData(dir, "Foo.java"); + VfsUtil.saveText(vFile, "class Foo {}"); + ((VirtualFileSystemEntry)vFile).setModificationStamp(0); // as unchanged file + + final Document document = FileDocumentManager.getInstance().getDocument(vFile); + assertTrue(document != null && document.getModificationStamp() == 0); + final GlobalSearchScope scope = GlobalSearchScope.projectScope(myProject); + assertNotNull(myJavaFacade.findClass("Foo", scope)); + + WriteCommandAction.runWriteCommandAction(myProject, new Runnable() { + @Override + public void run() { + document.insertString(0, "import Bar;\n"); + PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + assertNotNull(myJavaFacade.findClass("Foo", scope)); + } + }); + + final UndoManager undoManager = UndoManager.getInstance(getProject()); + final Editor editor = createEditor(vFile); + final FileEditor selectedEditor = new TextEditor() { + @NotNull + @Override + public Editor getEditor() { + return editor; + } + + @Override + public boolean canNavigateTo(@NotNull Navigatable navigatable) { + return false; + } + + @Override + public void navigateTo(@NotNull Navigatable navigatable) {} + + @NotNull + @Override + public JComponent getComponent() { + return null; + } + + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return null; + } + + @NotNull + @Override + public String getName() { + return null; + } + + @NotNull + @Override + public FileEditorState getState(@NotNull FileEditorStateLevel level) { + return null; + } + + @Override + public void setState(@NotNull FileEditorState state) {} + + @Override + public boolean isModified() { + return false; + } + + @Override + public boolean isValid() { + return false; + } + + @Override + public void selectNotify() {} + + @Override + public void deselectNotify() {} + + @Override + public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) {} + + @Override + public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) {} + + @Nullable + @Override + public BackgroundEditorHighlighter getBackgroundHighlighter() { + return null; + } + + @Nullable + @Override + public FileEditorLocation getCurrentLocation() { + return null; + } + + @Nullable + @Override + public StructureViewBuilder getStructureViewBuilder() { + return null; + } + + @Override + public void dispose() {} + + @Nullable + @Override + public T getUserData(@NotNull Key key) { + return null; + } + + @Override + public void putUserData(@NotNull Key key, @Nullable T value) {} + }; + + assertTrue(undoManager.isUndoAvailable(selectedEditor)); + FileDocumentManager.getInstance().saveDocument(document); + undoManager.undo(selectedEditor); + + assertNotNull(myJavaFacade.findClass("Foo", scope)); + } } From b179691a1bde9ed9a4ec54ec9fd2be65d66c87ef Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Wed, 22 Oct 2014 16:25:32 +0400 Subject: [PATCH 08/26] html viewer: don't check deprecated Nimbus L&F --- .../platform-impl/src/com/intellij/util/ui/SwingHelper.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java b/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java index 721e04469d24..488c52d14207 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java +++ b/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java @@ -436,13 +436,10 @@ public class SwingHelper { textPane.setContentType(UIUtil.HTML_MIME); textPane.setEditable(false); if (background != null) { - textPane.setBackground(background); // e.g. UIUtil.getOptionPaneBackground() + textPane.setBackground(background); } else { textPane.setOpaque(false); - if (UIUtil.isUnderNimbusLookAndFeel()) { - textPane.setBackground(UIUtil.TRANSPARENT_COLOR); - } } textPane.setForeground(foreground != null ? foreground : UIUtil.getLabelForeground()); return textPane; From b762b79d4b9de05e4320d7f0b566502610ea05eb Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 22 Oct 2014 13:47:50 +0400 Subject: [PATCH 09/26] WEB-13675 Do not insert redundant alignment between array elements and properties. This alignment included in ChildAttributes for new properties and array elements leads to spaces being inserted instead of tabs inside indents for corresponding blocks when both SMART_TABS and USE_TAB_CHARACTER options are active. Test data for tests of line movements was updated because it made use of these alignments. --- .../intellij/json/formatter/JsonBlock.java | 14 ++++++------- .../com/intellij/json/JsonEditingTest.java | 21 +++++++++++++++++++ ...dentWithTabsWhenSmartTabEnabled.after.json | 5 +++++ .../IndentWithTabsWhenSmartTabEnabled.json | 4 ++++ .../mover/ArraySelectionMovedDown.json | 7 +++++-- .../ArraySelectionMovedDown_afterDown.json | 7 +++++-- .../mover/ObjectSelectionMovedDown.json | 10 ++++++--- .../ObjectSelectionMovedDown_afterDown.json | 10 ++++++--- 8 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.after.json create mode 100644 json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.json diff --git a/json/src/com/intellij/json/formatter/JsonBlock.java b/json/src/com/intellij/json/formatter/JsonBlock.java index 2dccd347e177..8ffff7f2dc44 100644 --- a/json/src/com/intellij/json/formatter/JsonBlock.java +++ b/json/src/com/intellij/json/formatter/JsonBlock.java @@ -48,8 +48,6 @@ public class JsonBlock implements ASTBlock { // lazy initialized on first call to #getSubBlocks() private List mySubBlocks = null; - private final Alignment myChildAlignment = Alignment.createAlignment(); - private final Alignment myPropertyValueAlignment; private final Wrap myChildWrap; @@ -119,9 +117,8 @@ public class JsonBlock implements ASTBlock { JsonCodeStyleSettings customSettings = getCustomSettings(); if (isContainer() && childNodeType != JsonElementTypes.COMMA && !BRACES.contains(childNodeType)) { - assert myChildWrap != null && myChildAlignment != null; + assert myChildWrap != null; wrap = myChildWrap; - alignment = myChildAlignment; indent = Indent.getNormalIndent(); } // Handle properties alignment @@ -184,7 +181,10 @@ public class JsonBlock implements ASTBlock { @Override public ChildAttributes getChildAttributes(int newChildIndex) { if (isContainer()) { - return new ChildAttributes(Indent.getNormalIndent(), myChildAlignment); + // WEB-13675: For some reason including alignment in child attributes causes + // indents to consist solely of spaces when both USE_TABS and SMART_TAB + // options are enabled. + return new ChildAttributes(Indent.getNormalIndent(), null); } // Will use continuation indent for cases like { "foo" } return new ChildAttributes(null, null); @@ -192,8 +192,8 @@ public class JsonBlock implements ASTBlock { @Override public boolean isIncomplete() { - IElementType nodeType = myNode.getElementType(); - ASTNode lastChildNode = myNode.getLastChildNode(); + final IElementType nodeType = myNode.getElementType(); + final ASTNode lastChildNode = myNode.getLastChildNode(); if (nodeType == JsonElementTypes.OBJECT) { return lastChildNode != null && lastChildNode.getElementType() != JsonElementTypes.R_CURLY; } diff --git a/json/tests/test/com/intellij/json/JsonEditingTest.java b/json/tests/test/com/intellij/json/JsonEditingTest.java index bb6f5088c89c..42421979f490 100644 --- a/json/tests/test/com/intellij/json/JsonEditingTest.java +++ b/json/tests/test/com/intellij/json/JsonEditingTest.java @@ -3,6 +3,9 @@ package com.intellij.json; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import org.jetbrains.annotations.NotNull; /** @@ -37,4 +40,22 @@ public class JsonEditingTest extends JsonTestCase { public void testNormalIndentAfterPropertyWithoutComma() { doTest("\n"); } + + // WEB-13675 + public void testIndentWithTabsWhenSmartTabEnabled() { + CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(myFixture.getProject()); + CommonCodeStyleSettings.IndentOptions indentOptions = settings.getCommonSettings(JsonLanguage.INSTANCE).getIndentOptions(); + assertNotNull(indentOptions); + CommonCodeStyleSettings.IndentOptions oldSettings = (CommonCodeStyleSettings.IndentOptions)indentOptions.clone(); + indentOptions.TAB_SIZE = 4; + indentOptions.INDENT_SIZE = 4; + indentOptions.USE_TAB_CHARACTER = true; + indentOptions.SMART_TABS = true; + try { + doTest("\n\"baz\""); + } + finally { + indentOptions.copyFrom(oldSettings); + } + } } diff --git a/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.after.json b/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.after.json new file mode 100644 index 000000000000..152513cad497 --- /dev/null +++ b/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.after.json @@ -0,0 +1,5 @@ +{ + "foo": true, + "bar": false, + "baz" +} \ No newline at end of file diff --git a/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.json b/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.json new file mode 100644 index 000000000000..69824365e9e8 --- /dev/null +++ b/json/tests/testData/editing/IndentWithTabsWhenSmartTabEnabled.json @@ -0,0 +1,4 @@ +{ + "foo": true, + "bar": false, +} \ No newline at end of file diff --git a/json/tests/testData/mover/ArraySelectionMovedDown.json b/json/tests/testData/mover/ArraySelectionMovedDown.json index 476b56d42dea..81e4dc2bcd0e 100644 --- a/json/tests/testData/mover/ArraySelectionMovedDown.json +++ b/json/tests/testData/mover/ArraySelectionMovedDown.json @@ -1,5 +1,8 @@ [ - 1, [2], [true, - false], + 1, [2], + [ + true, + false + ], null ] \ No newline at end of file diff --git a/json/tests/testData/mover/ArraySelectionMovedDown_afterDown.json b/json/tests/testData/mover/ArraySelectionMovedDown_afterDown.json index 9db514b06905..1a7a49635d95 100644 --- a/json/tests/testData/mover/ArraySelectionMovedDown_afterDown.json +++ b/json/tests/testData/mover/ArraySelectionMovedDown_afterDown.json @@ -1,5 +1,8 @@ [ null, - 1, [2], [true, - false] + 1, [2], + [ + true, + false + ] ] \ No newline at end of file diff --git a/json/tests/testData/mover/ObjectSelectionMovedDown.json b/json/tests/testData/mover/ObjectSelectionMovedDown.json index 57efbe402072..ed363c1d3d6f 100644 --- a/json/tests/testData/mover/ObjectSelectionMovedDown.json +++ b/json/tests/testData/mover/ObjectSelectionMovedDown.json @@ -1,6 +1,10 @@ { - "foo": false, "bar": 42, - "baz": [1, 2, - 3], + "foo": false, + "bar": 42, + "baz": [ + 1, + 2, + 3 + ], "quux": null } \ No newline at end of file diff --git a/json/tests/testData/mover/ObjectSelectionMovedDown_afterDown.json b/json/tests/testData/mover/ObjectSelectionMovedDown_afterDown.json index 860d3b5d3783..ebf686822340 100644 --- a/json/tests/testData/mover/ObjectSelectionMovedDown_afterDown.json +++ b/json/tests/testData/mover/ObjectSelectionMovedDown_afterDown.json @@ -1,6 +1,10 @@ { + "foo": false, "quux": null, - "foo": false, "bar": 42, - "baz": [1, 2, - 3] + "bar": 42, + "baz": [ + 1, + 2, + 3 + ] } \ No newline at end of file From 9ec8fbb7d8603f4de70a5de9d3099e6cd3803b35 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 22 Oct 2014 15:54:31 +0400 Subject: [PATCH 10/26] WEB-13587 Align compound property values on opening brace/bracket Also updated test data with more complete example from user and changed preview shown in settings so effect was more clear. --- .../intellij/json/formatter/JsonBlock.java | 32 ++++++++++++------- .../json/formatter/JsonCodeStylePanel.java | 20 ++++++------ .../formatting/AlignPropertiesOnColon.json | 20 ++++++++++-- .../AlignPropertiesOnColon_after.json | 20 ++++++++++-- .../formatting/AlignPropertiesOnValue.json | 20 ++++++++++-- .../AlignPropertiesOnValue_after.json | 20 ++++++++++-- 6 files changed, 99 insertions(+), 33 deletions(-) diff --git a/json/src/com/intellij/json/formatter/JsonBlock.java b/json/src/com/intellij/json/formatter/JsonBlock.java index 8ffff7f2dc44..85bbe545f2bb 100644 --- a/json/src/com/intellij/json/formatter/JsonBlock.java +++ b/json/src/com/intellij/json/formatter/JsonBlock.java @@ -3,7 +3,6 @@ package com.intellij.json.formatter; import com.intellij.formatting.*; import com.intellij.json.JsonElementTypes; import com.intellij.json.JsonLanguage; -import com.intellij.json.JsonParserDefinition; import com.intellij.json.psi.JsonArray; import com.intellij.json.psi.JsonObject; import com.intellij.json.psi.JsonProperty; @@ -23,8 +22,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -import static com.intellij.json.JsonParserDefinition.JSON_BRACES; -import static com.intellij.json.JsonParserDefinition.JSON_BRACKETS; +import static com.intellij.json.JsonParserDefinition.*; import static com.intellij.json.formatter.JsonCodeStyleSettings.PropertyAlignment.ALIGN_ON_COLON; import static com.intellij.json.formatter.JsonCodeStyleSettings.PropertyAlignment.ALIGN_ON_VALUE; @@ -115,21 +113,31 @@ public class JsonBlock implements ASTBlock { Alignment alignment = null; Wrap wrap = null; - JsonCodeStyleSettings customSettings = getCustomSettings(); - if (isContainer() && childNodeType != JsonElementTypes.COMMA && !BRACES.contains(childNodeType)) { - assert myChildWrap != null; - wrap = myChildWrap; - indent = Indent.getNormalIndent(); + final JsonCodeStyleSettings customSettings = getCustomSettings(); + if (isContainer()) { + if (childNodeType != JsonElementTypes.COMMA && !BRACES.contains(childNodeType)) { + assert myChildWrap != null; + wrap = myChildWrap; + indent = Indent.getNormalIndent(); + } + else if (OPEN_BRACES.contains(childNodeType)) { + if (JsonPsiUtil.isPropertyValue(myPsiElement) && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_VALUE) { + // WEB-13587 Align compound values on opening brace/bracket, not the whole block + assert myParent != null && myParent.myParent != null && myParent.myParent.myPropertyValueAlignment != null; + alignment = myParent.myParent.myPropertyValueAlignment; + } + } } // Handle properties alignment else if (myNode.getElementType() == JsonElementTypes.PROPERTY) { - assert myParent.myNode.getElementType() == JsonElementTypes.OBJECT; - assert myParent.myPropertyValueAlignment != null; + assert myParent != null && myParent.myPropertyValueAlignment != null; if (childNode.getElementType() == JsonElementTypes.COLON && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_COLON) { alignment = myParent.myPropertyValueAlignment; } else if (JsonPsiUtil.isPropertyValue(childNode.getPsi()) && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_VALUE) { - alignment = myParent.myPropertyValueAlignment; + if (!JSON_CONTAINERS.contains(childNodeType)) { + alignment = myParent.myPropertyValueAlignment; + } } } return new JsonBlock(this, childNode, mySettings, alignment, indent, wrap); @@ -216,7 +224,7 @@ public class JsonBlock implements ASTBlock { } private boolean isContainer() { - return JsonParserDefinition.JSON_CONTAINERS.contains(myNode.getElementType()); + return JSON_CONTAINERS.contains(myNode.getElementType()); } private JsonCodeStyleSettings getCustomSettings() { diff --git a/json/src/com/intellij/json/formatter/JsonCodeStylePanel.java b/json/src/com/intellij/json/formatter/JsonCodeStylePanel.java index c5c78f78227b..fa858ab98d95 100644 --- a/json/src/com/intellij/json/formatter/JsonCodeStylePanel.java +++ b/json/src/com/intellij/json/formatter/JsonCodeStylePanel.java @@ -23,13 +23,16 @@ import java.awt.event.ItemListener; * @author Mikhail Golubev */ public class JsonCodeStylePanel extends CodeStyleAbstractPanel { - public static final String SAMPLE = "{\n" + - " \"longKeyName\": true,\n" + - " \"short\": false,\n" + - "\n" + - " \"group2-longKeyName\": null,\n" + - " \"group2-short\": 42\n" + - "}"; + public static final String ALIGNMENT_SAMPLE = "{\n" + + " \"foo\": {\n" + + " \"bar\": true,\n" + + " \"baz\": false\n" + + " },\n" + + " \"quux\": [\n" + + " 1, 2.0, 3e0, 4.0e0\n" + + " ],\n" + + " \"longPropertyName\": null\n" + + "}"; private JComboBox myPropertiesAlignmentCombo; private JPanel myPreviewPanel; @@ -59,7 +62,6 @@ public class JsonCodeStylePanel extends CodeStyleAbstractPanel { } } }); - } @Override @@ -82,7 +84,7 @@ public class JsonCodeStylePanel extends CodeStyleAbstractPanel { @Nullable @Override protected String getPreviewText() { - return SAMPLE; + return ALIGNMENT_SAMPLE; } @Override diff --git a/json/tests/testData/formatting/AlignPropertiesOnColon.json b/json/tests/testData/formatting/AlignPropertiesOnColon.json index e6bb1d6956be..c71adabb752f 100644 --- a/json/tests/testData/formatting/AlignPropertiesOnColon.json +++ b/json/tests/testData/formatting/AlignPropertiesOnColon.json @@ -1,5 +1,19 @@ { - "a": 1, - "aaa": 2, - "aaaaa": 3 + "require-dev": { + "phpunit/phpunit": "~3.7", + "phpunit/phpunit-selenium": "@stable", + "phpunit/phpunit-story": "@stable", + "phpunit/dbunit": "@stable" + }, + "minimum-stability": "dev", + "autoload": { + "psr-4": { + "DreamFactory\\Yii\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-develop": "1.5.x-dev" + } + } } \ No newline at end of file diff --git a/json/tests/testData/formatting/AlignPropertiesOnColon_after.json b/json/tests/testData/formatting/AlignPropertiesOnColon_after.json index d8c115391024..7a673e8c3c21 100644 --- a/json/tests/testData/formatting/AlignPropertiesOnColon_after.json +++ b/json/tests/testData/formatting/AlignPropertiesOnColon_after.json @@ -1,5 +1,19 @@ { - "a" : 1, - "aaa" : 2, - "aaaaa": 3 + "require-dev" : { + "phpunit/phpunit" : "~3.7", + "phpunit/phpunit-selenium": "@stable", + "phpunit/phpunit-story" : "@stable", + "phpunit/dbunit" : "@stable" + }, + "minimum-stability": "dev", + "autoload" : { + "psr-4": { + "DreamFactory\\Yii\\": "src/" + } + }, + "extra" : { + "branch-alias": { + "dev-develop": "1.5.x-dev" + } + } } \ No newline at end of file diff --git a/json/tests/testData/formatting/AlignPropertiesOnValue.json b/json/tests/testData/formatting/AlignPropertiesOnValue.json index e6bb1d6956be..c71adabb752f 100644 --- a/json/tests/testData/formatting/AlignPropertiesOnValue.json +++ b/json/tests/testData/formatting/AlignPropertiesOnValue.json @@ -1,5 +1,19 @@ { - "a": 1, - "aaa": 2, - "aaaaa": 3 + "require-dev": { + "phpunit/phpunit": "~3.7", + "phpunit/phpunit-selenium": "@stable", + "phpunit/phpunit-story": "@stable", + "phpunit/dbunit": "@stable" + }, + "minimum-stability": "dev", + "autoload": { + "psr-4": { + "DreamFactory\\Yii\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-develop": "1.5.x-dev" + } + } } \ No newline at end of file diff --git a/json/tests/testData/formatting/AlignPropertiesOnValue_after.json b/json/tests/testData/formatting/AlignPropertiesOnValue_after.json index 0cebf089466a..d4269bcc90b6 100644 --- a/json/tests/testData/formatting/AlignPropertiesOnValue_after.json +++ b/json/tests/testData/formatting/AlignPropertiesOnValue_after.json @@ -1,5 +1,19 @@ { - "a": 1, - "aaa": 2, - "aaaaa": 3 + "require-dev": { + "phpunit/phpunit": "~3.7", + "phpunit/phpunit-selenium": "@stable", + "phpunit/phpunit-story": "@stable", + "phpunit/dbunit": "@stable" + }, + "minimum-stability": "dev", + "autoload": { + "psr-4": { + "DreamFactory\\Yii\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-develop": "1.5.x-dev" + } + } } \ No newline at end of file From a2b4b60088943bb2e80922de71667041109edd08 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 22 Oct 2014 15:12:56 +0400 Subject: [PATCH 11/26] Add utility methods for unified comparison of element/node with element type --- .../intellij/json/formatter/JsonBlock.java | 50 ++++++++----------- .../com/intellij/json/psi/JsonPsiUtil.java | 32 ++++++++++++ 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/json/src/com/intellij/json/formatter/JsonBlock.java b/json/src/com/intellij/json/formatter/JsonBlock.java index 85bbe545f2bb..307e4a7fbc59 100644 --- a/json/src/com/intellij/json/formatter/JsonBlock.java +++ b/json/src/com/intellij/json/formatter/JsonBlock.java @@ -1,7 +1,6 @@ package com.intellij.json.formatter; import com.intellij.formatting.*; -import com.intellij.json.JsonElementTypes; import com.intellij.json.JsonLanguage; import com.intellij.json.psi.JsonArray; import com.intellij.json.psi.JsonObject; @@ -22,17 +21,19 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +import static com.intellij.json.JsonElementTypes.*; import static com.intellij.json.JsonParserDefinition.*; import static com.intellij.json.formatter.JsonCodeStyleSettings.PropertyAlignment.ALIGN_ON_COLON; import static com.intellij.json.formatter.JsonCodeStyleSettings.PropertyAlignment.ALIGN_ON_VALUE; +import static com.intellij.json.psi.JsonPsiUtil.hasElementType; /** * @author Mikhail Golubev */ public class JsonBlock implements ASTBlock { - private static final TokenSet OPEN_BRACES = TokenSet.create(JsonElementTypes.L_BRACKET, JsonElementTypes.L_CURLY); - private static final TokenSet CLOSE_BRACES = TokenSet.create(JsonElementTypes.R_BRACKET, JsonElementTypes.R_CURLY); - private static final TokenSet BRACES = TokenSet.orSet(OPEN_BRACES, CLOSE_BRACES); + private static final TokenSet JSON_OPEN_BRACES = TokenSet.create(L_BRACKET, L_CURLY); + private static final TokenSet JSON_CLOSE_BRACES = TokenSet.create(R_BRACKET, R_CURLY); + private static final TokenSet JSON_ALL_BRACES = TokenSet.orSet(JSON_OPEN_BRACES, JSON_CLOSE_BRACES); private final JsonBlock myParent; @@ -107,20 +108,18 @@ public class JsonBlock implements ASTBlock { } private Block makeSubBlock(@NotNull ASTNode childNode) { - final IElementType childNodeType = childNode.getElementType(); - Indent indent = Indent.getNoneIndent(); Alignment alignment = null; Wrap wrap = null; final JsonCodeStyleSettings customSettings = getCustomSettings(); - if (isContainer()) { - if (childNodeType != JsonElementTypes.COMMA && !BRACES.contains(childNodeType)) { + if (hasElementType(myNode, JSON_CONTAINERS)) { + if (!hasElementType(childNode, COMMA) && !hasElementType(childNode, JSON_ALL_BRACES)) { assert myChildWrap != null; wrap = myChildWrap; indent = Indent.getNormalIndent(); } - else if (OPEN_BRACES.contains(childNodeType)) { + else if (hasElementType(childNode, JSON_OPEN_BRACES)) { if (JsonPsiUtil.isPropertyValue(myPsiElement) && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_VALUE) { // WEB-13587 Align compound values on opening brace/bracket, not the whole block assert myParent != null && myParent.myParent != null && myParent.myParent.myPropertyValueAlignment != null; @@ -129,13 +128,13 @@ public class JsonBlock implements ASTBlock { } } // Handle properties alignment - else if (myNode.getElementType() == JsonElementTypes.PROPERTY) { + else if (hasElementType(myNode, PROPERTY) ) { assert myParent != null && myParent.myPropertyValueAlignment != null; - if (childNode.getElementType() == JsonElementTypes.COLON && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_COLON) { + if (hasElementType(childNode, COLON) && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_COLON) { alignment = myParent.myPropertyValueAlignment; } else if (JsonPsiUtil.isPropertyValue(childNode.getPsi()) && customSettings.PROPERTY_ALIGNMENT == ALIGN_ON_VALUE) { - if (!JSON_CONTAINERS.contains(childNodeType)) { + if (!hasElementType(childNode, JSON_CONTAINERS)) { alignment = myParent.myPropertyValueAlignment; } } @@ -165,17 +164,17 @@ public class JsonBlock implements ASTBlock { @Override public Spacing getSpacing(@Nullable Block child1, @NotNull Block child2) { final CommonCodeStyleSettings commonSettings = getCommonSettings(); - final IElementType leftChildType = child1 instanceof JsonBlock ? ((JsonBlock)child1).myNode.getElementType() : null; - final IElementType rightChildType = child2 instanceof JsonBlock ? ((JsonBlock)child2).myNode.getElementType() : null; + final ASTNode leftChild = child1 instanceof JsonBlock ? ((JsonBlock)child1).myNode : null; + final ASTNode rightChild = child2 instanceof JsonBlock ? ((JsonBlock)child2).myNode : null; // This causes braces/brackets to be on their own lines if whole object/array spans several lines. - if (leftChildType != null && rightChildType != null) { - if (JSON_BRACES.contains(leftChildType) ^ JSON_BRACES.contains(rightChildType)) { + if (leftChild != null && rightChild != null) { + if (hasElementType(leftChild, JSON_BRACES) ^ hasElementType(rightChild, JSON_BRACES)) { final int numSpaces = commonSettings.SPACE_WITHIN_BRACES ? 1 : 0; return Spacing.createDependentLFSpacing(numSpaces, numSpaces, myNode.getTextRange(), commonSettings.KEEP_LINE_BREAKS, commonSettings.KEEP_BLANK_LINES_IN_CODE); } - else if (JSON_BRACKETS.contains(leftChildType) ^ JSON_BRACKETS.contains(rightChildType)) { + else if (hasElementType(leftChild, JSON_BRACKETS) ^ hasElementType(rightChild, JSON_BRACKETS)) { final int numSpaces = commonSettings.SPACE_WITHIN_BRACKETS ? 1 : 0; return Spacing.createDependentLFSpacing(numSpaces, numSpaces, myNode.getTextRange(), commonSettings.KEEP_LINE_BREAKS, @@ -188,7 +187,7 @@ public class JsonBlock implements ASTBlock { @NotNull @Override public ChildAttributes getChildAttributes(int newChildIndex) { - if (isContainer()) { + if (hasElementType(myNode, JSON_CONTAINERS)) { // WEB-13675: For some reason including alignment in child attributes causes // indents to consist solely of spaces when both USE_TABS and SMART_TAB // options are enabled. @@ -200,15 +199,14 @@ public class JsonBlock implements ASTBlock { @Override public boolean isIncomplete() { - final IElementType nodeType = myNode.getElementType(); final ASTNode lastChildNode = myNode.getLastChildNode(); - if (nodeType == JsonElementTypes.OBJECT) { - return lastChildNode != null && lastChildNode.getElementType() != JsonElementTypes.R_CURLY; + if (hasElementType(myNode, OBJECT)) { + return lastChildNode != null && lastChildNode.getElementType() != R_CURLY; } - else if (nodeType == JsonElementTypes.ARRAY) { - return lastChildNode != null && lastChildNode.getElementType() != JsonElementTypes.R_BRACKET; + else if (hasElementType(myNode, ARRAY)) { + return lastChildNode != null && lastChildNode.getElementType() != R_BRACKET; } - else if (myPsiElement instanceof JsonProperty) { + else if (hasElementType(myNode, PROPERTY)) { return ((JsonProperty)myPsiElement).getValue() == null; } return false; @@ -223,10 +221,6 @@ public class JsonBlock implements ASTBlock { return node.getElementType() == TokenType.WHITE_SPACE || node.getTextLength() == 0; } - private boolean isContainer() { - return JSON_CONTAINERS.contains(myNode.getElementType()); - } - private JsonCodeStyleSettings getCustomSettings() { return mySettings.getCustomSettings(JsonCodeStyleSettings.class); } diff --git a/json/src/com/intellij/json/psi/JsonPsiUtil.java b/json/src/com/intellij/json/psi/JsonPsiUtil.java index e3520f7526b1..0b9a151212e6 100644 --- a/json/src/com/intellij/json/psi/JsonPsiUtil.java +++ b/json/src/com/intellij/json/psi/JsonPsiUtil.java @@ -5,6 +5,7 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.TokenType; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import static com.intellij.json.JsonParserDefinition.JSON_COMMENTARIES; @@ -86,4 +87,35 @@ public class JsonPsiUtil { } return lastSeen.getPsi(); } + + /** + * Check that element type of the given AST node belongs to the token set. + *

+ * It slightly less verbose than {@code set.contains(node.getElementType())} and overloaded methods with the same name + * allow check ASTNode/PsiElement against both concrete element types and token sets in uniform way. + */ + public static boolean hasElementType(@NotNull ASTNode node, @NotNull TokenSet set) { + return set.contains(node.getElementType()); + } + + /** + * @see #hasElementType(com.intellij.lang.ASTNode, com.intellij.psi.tree.TokenSet) + */ + public static boolean hasElementType(@NotNull ASTNode node, IElementType... types) { + return hasElementType(node, TokenSet.create(types)); + } + + /** + * @see #hasElementType(com.intellij.lang.ASTNode, com.intellij.psi.tree.TokenSet) + */ + public static boolean hasElementType(@NotNull PsiElement element, @NotNull TokenSet set) { + return element.getNode() != null && hasElementType(element.getNode(), set); + } + + /** + * @see #hasElementType(com.intellij.lang.ASTNode, com.intellij.psi.tree.IElementType...) + */ + public static boolean hasElementType(@NotNull PsiElement element, IElementType... types) { + return element.getNode() != null && hasElementType(element.getNode(), types); + } } From 679c59f06fb4b89cb2949bfcb014ea1c38b7ee49 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 22 Oct 2014 16:58:05 +0400 Subject: [PATCH 12/26] [git] IDEA-131705 Fix a misprint :( If there is no error, do change the target --- plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java b/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java index 40eaf69b9f7b..aa03697963c8 100644 --- a/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java +++ b/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java @@ -182,7 +182,7 @@ class GitPushTargetPanel extends PushTargetPanel { @Override public void fireOnChange() { - if (myError == null) { + if (myError != null) { return; } String remoteName = myRemoteLabel.getText(); From 78380e948d3ca6fadf94f21699834d943c87db11 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Wed, 22 Oct 2014 14:55:51 +0200 Subject: [PATCH 13/26] less verbose test --- .../testSrc/com/intellij/index/IndexTest.java | 113 ++---------------- 1 file changed, 10 insertions(+), 103 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.java b/java/java-tests/testSrc/com/intellij/index/IndexTest.java index f561fef91882..b3be1f9f4feb 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.java +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.java @@ -15,22 +15,21 @@ */ package com.intellij.index; -import com.intellij.codeHighlighting.BackgroundEditorHighlighter; import com.intellij.codeInsight.CodeInsightTestCase; -import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.command.impl.CurrentEditorProvider; +import com.intellij.openapi.command.impl.UndoManagerImpl; import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.*; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileTypes.PlainTextFileType; import com.intellij.openapi.util.Factory; -import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry; -import com.intellij.pom.Navigatable; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.search.GlobalSearchScope; @@ -42,10 +41,7 @@ import com.intellij.util.indexing.MapIndexStorage; import com.intellij.util.indexing.StorageException; import com.intellij.util.io.*; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import java.beans.PropertyChangeListener; import java.io.DataInput; import java.io.DataOutput; import java.io.File; @@ -311,7 +307,6 @@ public class IndexTest extends CodeInsightTestCase { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); assertEquals(" Foo", file.getText()); assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo")); - } }); } @@ -339,101 +334,13 @@ public class IndexTest extends CodeInsightTestCase { }); final UndoManager undoManager = UndoManager.getInstance(getProject()); - final Editor editor = createEditor(vFile); - final FileEditor selectedEditor = new TextEditor() { - @NotNull + final FileEditor selectedEditor = FileEditorManager.getInstance(myProject).openFile(vFile, false)[0]; + ((UndoManagerImpl)undoManager).setEditorProvider(new CurrentEditorProvider() { @Override - public Editor getEditor() { - return editor; + public FileEditor getCurrentEditor() { + return selectedEditor; } - - @Override - public boolean canNavigateTo(@NotNull Navigatable navigatable) { - return false; - } - - @Override - public void navigateTo(@NotNull Navigatable navigatable) {} - - @NotNull - @Override - public JComponent getComponent() { - return null; - } - - @Nullable - @Override - public JComponent getPreferredFocusedComponent() { - return null; - } - - @NotNull - @Override - public String getName() { - return null; - } - - @NotNull - @Override - public FileEditorState getState(@NotNull FileEditorStateLevel level) { - return null; - } - - @Override - public void setState(@NotNull FileEditorState state) {} - - @Override - public boolean isModified() { - return false; - } - - @Override - public boolean isValid() { - return false; - } - - @Override - public void selectNotify() {} - - @Override - public void deselectNotify() {} - - @Override - public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) {} - - @Override - public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) {} - - @Nullable - @Override - public BackgroundEditorHighlighter getBackgroundHighlighter() { - return null; - } - - @Nullable - @Override - public FileEditorLocation getCurrentLocation() { - return null; - } - - @Nullable - @Override - public StructureViewBuilder getStructureViewBuilder() { - return null; - } - - @Override - public void dispose() {} - - @Nullable - @Override - public T getUserData(@NotNull Key key) { - return null; - } - - @Override - public void putUserData(@NotNull Key key, @Nullable T value) {} - }; + }); assertTrue(undoManager.isUndoAvailable(selectedEditor)); FileDocumentManager.getInstance().saveDocument(document); From 7b940b6f91a86bb0195cb044a38d87120ef0cb8b Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 22 Oct 2014 17:06:12 +0400 Subject: [PATCH 14/26] IDEA-131712 Debugger is showing current position on evaluate --- .../src/com/intellij/xdebugger/impl/frame/XFramesView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java index 4fb2b75c13a0..77e154a329c2 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java @@ -121,6 +121,7 @@ public class XFramesView extends XDebugView { XDebugSession session = getSession(e); if (session != null) { mySelectedFrameIndex = 0; + myRefresh = false; updateFrames((XExecutionStack)item, session); } } @@ -305,7 +306,7 @@ public class XFramesView extends XDebugView { Object selected = myFramesList.getSelectedValue(); if (selected instanceof XStackFrame) { if (session != null) { - if (force || !myRefresh) { + if (force || (!myRefresh && session.getCurrentStackFrame() != selected)) { session.setCurrentStackFrame(mySelectedStack, (XStackFrame)selected, mySelectedFrameIndex == 0); } } From b73348f83c353078d05fd0b8b58dda0ebe8eb2f0 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 22 Oct 2014 17:03:55 +0400 Subject: [PATCH 15/26] IDEA-131732 Update label in "Server Certificates" configurable --- .../com/intellij/util/net/ssl/CertificateConfigurable.form | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-api/src/com/intellij/util/net/ssl/CertificateConfigurable.form b/platform/platform-api/src/com/intellij/util/net/ssl/CertificateConfigurable.form index 18c12cb56090..fc148671aeab 100644 --- a/platform/platform-api/src/com/intellij/util/net/ssl/CertificateConfigurable.form +++ b/platform/platform-api/src/com/intellij/util/net/ssl/CertificateConfigurable.form @@ -3,7 +3,7 @@ - + @@ -56,7 +56,7 @@ - + From dfcbd14bb077acf22e9a53963073589bdae93324 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 22 Oct 2014 17:07:41 +0400 Subject: [PATCH 16/26] UP-2253 --- .../xml/impl/schema/XmlElementDescriptorImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java index 7bf9f02710b3..49d3c4c12245 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java @@ -219,7 +219,6 @@ public class XmlElementDescriptorImpl extends XsdEnumerationDescriptor if (type instanceof ComplexTypeDescriptor) { final ComplexTypeDescriptor descriptor = (ComplexTypeDescriptor)type; - String contextNs; PsiFile containingFile = context != null ? context.getContainingFile():null; if (context != null && !containingFile.isPhysical()) { @@ -227,10 +226,11 @@ public class XmlElementDescriptorImpl extends XsdEnumerationDescriptor //context = context.getParentTag(); } + String contextNs; if (context != null && - ( descriptor.canContainTag(context.getLocalName(), contextNs = context.getNamespace(), context ) && - (!contextNs.equals(getNamespace()) || descriptor.hasAnyInContentModel()) - ) ) { + descriptor.canContainTag(context.getLocalName(), contextNs = context.getNamespace(), context) && + (!contextNs.equals(getNamespace()) || descriptor.hasAnyInContentModel()) && + containingFile instanceof XmlFile) { // JSXmlLiteralExpressionImpl is crazy final XmlNSDescriptor nsDescriptor = getNSDescriptor(); if (nsDescriptor != null) { From b69b10a65d7e01d78cdbd4b7afbee183128f4322 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 22 Oct 2014 14:33:15 +0200 Subject: [PATCH 17/26] back reference is two words --- .../intellij/lang/regexp/validation/RegExpAnnotator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java b/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java index 1d32bf8ab6eb..d326d2c28557 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/validation/RegExpAnnotator.java @@ -124,14 +124,14 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot public void visitRegExpBackref(final RegExpBackref backref) { final RegExpGroup group = backref.resolve(); if (group == null) { - final Annotation a = myHolder.createErrorAnnotation(backref, "Unresolved backreference"); + final Annotation a = myHolder.createErrorAnnotation(backref, "Unresolved back reference"); if (a != null) { // IDEA-9381 a.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL); } } else if (PsiTreeUtil.isAncestor(group, backref, true)) { - myHolder.createWarningAnnotation(backref, "Backreference is nested into the capturing group it refers to"); + myHolder.createWarningAnnotation(backref, "Back reference is nested into the capturing group it refers to"); } } @@ -173,7 +173,7 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot */ final RegExpGroup group = groupRef.resolve(); if (group == null) { - final Annotation a = myHolder.createErrorAnnotation(groupRef, "Unresolved backreference"); + final Annotation a = myHolder.createErrorAnnotation(groupRef, "Unresolved back reference"); if (a != null) { // IDEA-9381 a.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL); From 49dfd377d1e801bb8d301d9d2006081d5669dcb9 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 22 Oct 2014 14:38:11 +0200 Subject: [PATCH 18/26] regexp: brace matching for named groups (IDEA-124018) --- .../src/org/intellij/lang/regexp/RegExpBraceMatcher.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpBraceMatcher.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpBraceMatcher.java index 748458d218d5..c815d4bc9c48 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpBraceMatcher.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpBraceMatcher.java @@ -30,6 +30,8 @@ public class RegExpBraceMatcher implements PairedBraceMatcher { new BracePair(RegExpTT.POS_LOOKBEHIND, RegExpTT.GROUP_END, true), new BracePair(RegExpTT.NEG_LOOKBEHIND, RegExpTT.GROUP_END, true), new BracePair(RegExpTT.PYTHON_NAMED_GROUP, RegExpTT.GROUP_END, true), new BracePair(RegExpTT.PYTHON_NAMED_GROUP_REF, RegExpTT.GROUP_END, true), + new BracePair(RegExpTT.RUBY_NAMED_GROUP, RegExpTT.GROUP_END, true), + new BracePair(RegExpTT.RUBY_QUOTED_NAMED_GROUP, RegExpTT.GROUP_END, true), new BracePair(RegExpTT.CLASS_BEGIN, RegExpTT.CLASS_END, false), new BracePair(RegExpTT.LBRACE, RegExpTT.RBRACE, false), new BracePair(RegExpTT.QUOTE_BEGIN, RegExpTT.QUOTE_END, false),}; } From 6239e6086ac33e83e52f5d6b6feef9b3eaa64f94 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 22 Oct 2014 15:16:33 +0200 Subject: [PATCH 19/26] java regex does not support Ruby quoted named group syntax --- .../src/org/intellij/lang/regexp/psi/RegExpGroup.java | 2 ++ .../org/intellij/lang/regexp/psi/impl/RegExpGroupImpl.java | 4 ++++ java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/RegExpSupport/src/org/intellij/lang/regexp/psi/RegExpGroup.java b/RegExpSupport/src/org/intellij/lang/regexp/psi/RegExpGroup.java index d1afd4e05b79..c0a1278b72dd 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/psi/RegExpGroup.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/psi/RegExpGroup.java @@ -29,6 +29,8 @@ public interface RegExpGroup extends RegExpAtom { boolean isRubyNamedGroup(); + boolean isNamedGroup(); + @Nullable String getGroupName(); } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpGroupImpl.java b/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpGroupImpl.java index b24669757917..023f64cf16b2 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpGroupImpl.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/psi/impl/RegExpGroupImpl.java @@ -56,6 +56,10 @@ public class RegExpGroupImpl extends RegExpElementImpl implements RegExpGroup { getNode().findChildByType(RegExpTT.RUBY_QUOTED_NAMED_GROUP) != null; } + public boolean isNamedGroup() { + return getNode().findChildByType(RegExpTT.RUBY_NAMED_GROUP) != null; + } + public String getGroupName() { if (!isPythonNamedGroup()) { return null; diff --git a/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java b/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java index 21a03d7e2bc3..86ca15a074dd 100644 --- a/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java +++ b/java/java-impl/src/com/intellij/psi/impl/JavaRegExpHost.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -60,7 +60,7 @@ public class JavaRegExpHost implements RegExpLanguageHost { @Override public boolean supportsNamedGroupSyntax(RegExpGroup group) { - if (group.isRubyNamedGroup()) { + if (group.isNamedGroup()) { final Module module = ModuleUtilCore.findModuleForPsiElement(group); if (module != null) { final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); From a3b5205ae4bd195839b42320b48c613b4e8aa64c Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 22 Oct 2014 15:22:22 +0200 Subject: [PATCH 20/26] regex: highlight groups as parentheses (IDEA-124018) --- .../org/intellij/lang/regexp/RegExpHighlighter.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java index fd3a8b03bd22..971cf56755fe 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java @@ -120,6 +120,16 @@ public class RegExpHighlighter extends SyntaxHighlighterBase { keys1.put(RegExpTT.QUOTE_BEGIN, QUOTE_CHARACTER); keys1.put(RegExpTT.QUOTE_END, QUOTE_CHARACTER); + keys1.put(RegExpTT.NON_CAPT_GROUP, PARENTHS); + keys1.put(RegExpTT.POS_LOOKBEHIND, PARENTHS); + keys1.put(RegExpTT.NEG_LOOKBEHIND, PARENTHS); + keys1.put(RegExpTT.POS_LOOKAHEAD, PARENTHS); + keys1.put(RegExpTT.NEG_LOOKAHEAD, PARENTHS); + keys1.put(RegExpTT.SET_OPTIONS, PARENTHS); + keys1.put(RegExpTT.PYTHON_NAMED_GROUP, PARENTHS); + keys1.put(RegExpTT.PYTHON_NAMED_GROUP_REF, PARENTHS); + keys1.put(RegExpTT.RUBY_NAMED_GROUP, PARENTHS); + keys1.put(RegExpTT.RUBY_QUOTED_NAMED_GROUP, PARENTHS); keys1.put(RegExpTT.GROUP_BEGIN, PARENTHS); keys1.put(RegExpTT.GROUP_END, PARENTHS); From 16ab0a8322c19010473b557245fcd1f155cdc1ee Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Wed, 22 Oct 2014 15:25:24 +0200 Subject: [PATCH 21/26] Project View: sort directories by type as well (e.g. OS X bundles .app, .framework) --- .../intellij/projectView/ProjectTreeSortingTest.java | 10 +++++----- .../ide/projectView/impl/nodes/PsiDirectoryNode.java | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/projectView/ProjectTreeSortingTest.java b/java/java-tests/testSrc/com/intellij/projectView/ProjectTreeSortingTest.java index cc06d15c396e..b25ca382f2fb 100644 --- a/java/java-tests/testSrc/com/intellij/projectView/ProjectTreeSortingTest.java +++ b/java/java-tests/testSrc/com/intellij/projectView/ProjectTreeSortingTest.java @@ -132,11 +132,11 @@ public class ProjectTreeSortingTest extends BaseProjectViewTestCase { ((ProjectViewImpl)myProjectView).setFoldersAlwaysOnTop(false); assertTree("-foldersOnTop\n" + " a.java\n" + + " +b.java\n" + " c.java\n" + " a.txt\n" + - " c.txt\n" + - " +b.java\n" + - " +b.txt\n"); + " +b.txt\n"+ + " c.txt\n"); } public void testSortByTypeBetweenFilesAndFolders() throws Exception { @@ -156,11 +156,11 @@ public class ProjectTreeSortingTest extends BaseProjectViewTestCase { assertTree("-sortByTypeBetweenFilesAndFolders\n" + " a.java\n" + " b.java\n" + + " +a.java_folder\n" + + " +b.java_folder\n" + " a.txt\n" + " b.txt\n" + - " +a.java_folder\n" + " +a_folder\n" + - " +b.java_folder\n" + " +b_folder\n"); } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java index 16aa930b806a..ec0b9dd8b6c6 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java @@ -318,6 +318,14 @@ public class PsiDirectoryNode extends BasePsiNode implements Navig return null; } + @Override + public Comparable getTypeSortKey() { + VirtualFile file = getVirtualFile(); + if (file == null) return null; + String extension = file.getExtension(); + return extension == null ? null : new PsiFileNode.ExtensionSortKey(extension); + } + @Override public String getQualifiedNameSortKey() { final PsiDirectoryFactory factory = PsiDirectoryFactory.getInstance(getProject()); From 34abbd85c020fbf69b320487fb676fd4b8ef4688 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Wed, 22 Oct 2014 17:49:47 +0400 Subject: [PATCH 22/26] invoke FileEditorProvider.accept() from read action --- .../fileEditor/impl/FileEditorManagerImpl.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index c4ac427f89b5..0dc4f5bc7209 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -771,15 +771,13 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec try { final FileEditorProvider provider = newProviders[i]; LOG.assertTrue(provider != null, "Provider for file "+file+" is null. All providers: "+Arrays.asList(newProviders)); - LOG.assertTrue(provider.accept(myProject, file), "Provider " + provider + " doesn't accept file " + file); - if ((provider instanceof AsyncFileEditorProvider)) { - builders[i] = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public AsyncFileEditorProvider.Builder compute() { - return ((AsyncFileEditorProvider)provider).createEditorAsync(myProject, file); - } - }); - } + builders[i] = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public AsyncFileEditorProvider.Builder compute() { + LOG.assertTrue(provider.accept(myProject, file), "Provider " + provider + " doesn't accept file " + file); + return provider instanceof AsyncFileEditorProvider ? ((AsyncFileEditorProvider)provider).createEditorAsync(myProject, file) : null; + } + }); } catch (Exception e) { LOG.error(e); From 9bb274c2696a3f7df93dc822c84794e5d2cdc600 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Wed, 22 Oct 2014 18:22:39 +0400 Subject: [PATCH 23/26] IDEA-92343 File Structure popup appears on wrong monitor --- .../openapi/util/DimensionService.java | 18 +++++++++--------- .../com/intellij/ui/popup/AbstractPopup.java | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/util/DimensionService.java b/platform/platform-api/src/com/intellij/openapi/util/DimensionService.java index 715b703e2321..5844767aac87 100644 --- a/platform/platform-api/src/com/intellij/openapi/util/DimensionService.java +++ b/platform/platform-api/src/com/intellij/openapi/util/DimensionService.java @@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.WindowManager; import com.intellij.ui.ScreenUtil; import com.intellij.util.containers.hash.LinkedHashMap; @@ -252,15 +253,14 @@ public class DimensionService implements PersistentStateComponent { } JFrame frame = null; - if (project == null) { - final Component owner = IdeFocusManager.findInstance().getFocusOwner(); - if (owner != null) { - frame = UIUtil.getParentOfType(JFrame.class, owner); - } - if (frame == null) { - frame = WindowManager.getInstance().findVisibleFrame(); - } - } else { + final Component owner = IdeFocusManager.findInstance().getFocusOwner(); + if (owner != null) { + frame = UIUtil.getParentOfType(JFrame.class, owner); + } + if (frame == null) { + frame = WindowManager.getInstance().findVisibleFrame(); + } + if (project != null && (frame == null || (frame instanceof IdeFrame && project != ((IdeFrame)frame).getProject()))) { frame = WindowManager.getInstance().getFrame(project); } Rectangle screen = new Rectangle(0, 0, 0, 0); diff --git a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java index 7274d0930824..039868096f10 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java @@ -747,7 +747,7 @@ public class AbstractPopup implements JBPopup { Point xy = new Point(aScreenX, aScreenY); boolean adjustXY = true; - if (myDimensionServiceKey != null) { + if (myUseDimServiceForXYLocation && myDimensionServiceKey != null) { final Point storedLocation = DimensionService.getInstance().getLocation(myDimensionServiceKey, myProject); if (storedLocation != null) { xy = storedLocation; From 9679d0e594fc7da1aaa9b43b503f374e07588abf Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 22 Oct 2014 18:45:21 +0400 Subject: [PATCH 24/26] decompiler: more correct toString --- .../org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java index 44c58f04e196..13658580fe4e 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java @@ -82,6 +82,7 @@ public class ControlFlowGraph implements CodeConstants { } public String toString() { + if (blocks == null) return "Empty"; String new_line_separator = DecompilerContext.getNewLineSeparator(); From 9c1a6769f516413b33848cfe996f6485ec7b4ccd Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 17 Oct 2014 21:33:08 +0400 Subject: [PATCH 25/26] deserialization of type-specific inner properties: don't pass 'null' to 'loadState' --- .../openapi/components/ComponentSerializationUtil.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/core-impl/src/com/intellij/openapi/components/ComponentSerializationUtil.java b/platform/core-impl/src/com/intellij/openapi/components/ComponentSerializationUtil.java index 33eee1a79178..0093d0016881 100644 --- a/platform/core-impl/src/com/intellij/openapi/components/ComponentSerializationUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/components/ComponentSerializationUtil.java @@ -35,7 +35,10 @@ public class ComponentSerializationUtil { public static void loadComponentState(@NotNull PersistentStateComponent configuration, @Nullable Element element) { if (element != null) { Class stateClass = getStateClass(configuration.getClass()); - configuration.loadState(XmlSerializer.deserialize(element, stateClass)); + S state = XmlSerializer.deserialize(element, stateClass); + if (state != null) { + configuration.loadState(state); + } } } } From 542aa23b043654eb6b7366ea8f9cbdd4476827f1 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 22 Oct 2014 17:38:07 +0200 Subject: [PATCH 26/26] continue Firefox RDP --- .../jetbrains/rpc/ChannelBufferToString.java | 11 ++- .../src/org/jetbrains/rpc/MessageDecoder.java | 87 ++++++++++++++++++ .../connection/RemoteVmConnection.java | 49 +++++++++++ .../debugger/connection/VmConnection.java | 1 - .../src/org/jetbrains/io/JsonReaderEx.java | 22 +++-- .../jsonProtocol/JsonParseMethod.java | 1 - .../protocol-reader/protocol-reader.iml | 6 +- .../protocolReader/AbsentSubtypeAspect.java | 29 ------ .../protocolReader/DynamicReader.java | 45 +++++----- .../protocolReader/ExistingSubtypeAspect.java | 8 +- .../protocolReader/FieldProcessor.java | 17 +--- .../jetbrains/protocolReader/GlobalScope.java | 3 +- .../protocolReader/InterfaceReader.java | 5 +- .../protocolReader/MethodHandler.java | 17 ++-- .../protocolReader/ObjectValueReader.java | 2 +- .../protocolReader/ReadDelegate.java | 17 +++- .../protocolReader/ReaderGenerator.java | 19 ++-- .../jetbrains/protocolReader/ReaderRoot.java | 9 +- .../protocolReader/SubtypeAspect.java | 19 ---- .../jetbrains/protocolReader/TypeHandler.java | 88 ++++++++++++------- .../org/jetbrains/protocolReader/Util.java | 6 +- 21 files changed, 296 insertions(+), 165 deletions(-) create mode 100644 platform/script-debugger/backend/src/org/jetbrains/rpc/MessageDecoder.java delete mode 100644 platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/AbsentSubtypeAspect.java delete mode 100644 platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/SubtypeAspect.java diff --git a/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java b/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java index 0b18ebcd1eb2..bb776e55ea20 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java +++ b/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java @@ -3,6 +3,8 @@ package org.jetbrains.rpc; import com.intellij.util.text.StringFactory; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.nio.ByteBuffer; import java.nio.CharBuffer; @@ -29,7 +31,7 @@ public final class ChannelBufferToString { } } - public static CharBuffer readIntoCharBuffer(CharBuffer charBuffer, ByteBuf buffer, int byteCount) { + public static CharBuffer readIntoCharBuffer(@Nullable CharBuffer charBuffer, @NotNull ByteBuf buffer, int byteCount) { CharsetDecoder decoder = CharsetUtil.getDecoder(CharsetUtil.UTF_8); ByteBuffer in = buffer.nioBuffer(buffer.readerIndex(), byteCount); if (charBuffer == null) { @@ -52,4 +54,11 @@ public final class ChannelBufferToString { buffer.skipBytes(byteCount); return charBuffer; } + + public static void writeIntAsAscii(int value, @NotNull ByteBuf buffer) { + String string = Integer.toString(value); + for (int i = 0; i < string.length(); i++) { + buffer.writeByte(string.charAt(i)); + } + } } \ No newline at end of file diff --git a/platform/script-debugger/backend/src/org/jetbrains/rpc/MessageDecoder.java b/platform/script-debugger/backend/src/org/jetbrains/rpc/MessageDecoder.java new file mode 100644 index 000000000000..9d7e35198225 --- /dev/null +++ b/platform/script-debugger/backend/src/org/jetbrains/rpc/MessageDecoder.java @@ -0,0 +1,87 @@ +package org.jetbrains.rpc; + +import io.netty.buffer.ByteBuf; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.io.SimpleChannelInboundHandlerAdapter; + +import java.nio.CharBuffer; + +public abstract class MessageDecoder extends SimpleChannelInboundHandlerAdapter { + protected int contentLength; + protected final StringBuilder builder = new StringBuilder(64); + + private CharBuffer chunkedContent; + private int consumedContentByteCount = 0; + + protected final int parseContentLength() { + return parseInt(builder, 0, false, 10); + } + + @Nullable + protected String doReadContent(@NotNull ByteBuf buffer) { + int required = contentLength - consumedContentByteCount; + String result; + if (buffer.readableBytes() < required) { + if (chunkedContent == null) { + chunkedContent = CharBuffer.allocate(contentLength); + } + + int count = buffer.readableBytes(); + ChannelBufferToString.readIntoCharBuffer(chunkedContent, buffer, count); + consumedContentByteCount += count; + return null; + } + else if (chunkedContent != null) { + ChannelBufferToString.readIntoCharBuffer(chunkedContent, buffer, required); + result = ChannelBufferToString.charBufferToString(chunkedContent); + + chunkedContent = null; + consumedContentByteCount = 0; + return result; + } + else { + // we can produce char sequence CharSequence result = CharsetUtil.UTF_8.decode(buffer.toByteBuffer(buffer.readerIndex(), required)); + // but later, in JsonReaderEx, it will be toString in any case, so, in this case, intermediate java.nio.HeapCharBuffer will be created - so, we stay with String + return ChannelBufferToString.readString(buffer, required); + } + } + + /** + * Javolution - Java(TM) Solution for Real-Time and Embedded Systems + * Copyright (C) 2006 - Javolution (http://javolution.org/) + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software is + * freely granted, provided that this notice is preserved. + */ + private static int parseInt(final CharSequence value, final int start, final boolean isNegative, final int radix) { + final int end = value.length(); + int result = 0; // Accumulates negatively (avoid MIN_VALUE overflow). + int i = start; + for (; i < end; i++) { + char c = value.charAt(i); + int digit = (c <= '9') ? c - '0' + : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10 + : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10 : -1; + if ((digit >= 0) && (digit < radix)) { + int newResult = result * radix - digit; + if (newResult > result) { + throw new NumberFormatException("Overflow parsing " + value.subSequence(start, end)); + } + result = newResult; + } + else { + break; + } + } + // Requires one valid digit character and checks for opposite overflow. + if ((result == 0) && ((end == 0) || (value.charAt(i - 1) != '0'))) { + throw new NumberFormatException("Invalid integer representation for " + value.subSequence(start, end)); + } + if ((result == Integer.MIN_VALUE) && !isNegative) { + throw new NumberFormatException("Overflow parsing " + value.subSequence(start, end)); + } + return isNegative ? result : -result; + } +} \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java index 6557de5130fe..753ec0c05cb9 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java @@ -2,15 +2,22 @@ package org.jetbrains.debugger.connection; import com.intellij.ide.browsers.WebBrowser; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.AsyncResult; +import com.intellij.ui.ColoredListCellRenderer; +import com.intellij.ui.components.JBList; import com.intellij.util.Consumer; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.socketConnection.ConnectionStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.debugger.Vm; +import javax.swing.*; import java.net.InetSocketAddress; +import java.util.Collection; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicReference; @@ -87,4 +94,46 @@ public abstract class RemoteVmConnection extends VmConnection { } return callback; } + + @NotNull + public static AsyncResult chooseDebuggee(@NotNull final Collection targets, final int selectedIndex, @NotNull final Function itemToString) { + if (targets.size() == 1) { + return AsyncResult.done(ContainerUtil.getFirstItem(targets)); + } + + final AsyncResult result = new AsyncResult(); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + final JBList list = new JBList(targets); + list.setCellRenderer(new ColoredListCellRenderer() { + @Override + protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { + //noinspection unchecked + append(itemToString.fun((T)value)); + } + }); + list.setSelectedIndex(selectedIndex); + + JBPopupFactory.getInstance(). + createListPopupBuilder(list). + setTitle("Choose Page to debug"). + setItemChoosenCallback(new Runnable() { + @Override + public void run() { + @SuppressWarnings("unchecked") + T value = (T)list.getSelectedValue(); + if (value == null) { + result.setRejected(); + } + else { + result.setDone(value); + } + } + }). + createPopup().showInFocusCenter(); + } + }); + return result; + } } \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java index 7a6c17169e7f..6f7d14c65100 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java @@ -24,7 +24,6 @@ public abstract class VmConnection implements Disposable, BrowserC protected volatile T vm; private final ActionCallback opened = new ActionCallback(); - private final AtomicBoolean closed = new AtomicBoolean(); public final Vm getVm() { diff --git a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java index 7dad7854ca0d..eaf83b872be8 100644 --- a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java +++ b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java @@ -665,6 +665,15 @@ public final class JsonReaderEx implements Closeable { * Returns the next token, a {@link JsonToken#NAME property name}, and consumes it */ public String nextName() { + String result = nextNameOrNull(); + if (result == null) { + throw createParseError("Expected a name but was " + peek()); + } + return result; + } + + @Nullable + public String nextNameOrNull() { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -680,7 +689,10 @@ public final class JsonReaderEx implements Closeable { result = nextQuotedValue('"'); } else { - throw createParseError("Expected a name but was " + peek()); + if (p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY) { + throw createParseError("Expected a name but was " + peek()); + } + return null; } peeked = PEEKED_NONE; return result; @@ -713,6 +725,7 @@ public final class JsonReaderEx implements Closeable { return in.charAt(offset + index); } + @NotNull @Override public CharSequence subSequence(int start, int end) { if ((end - start) > length) { @@ -1153,6 +1166,7 @@ public final class JsonReaderEx implements Closeable { /** * Closes this JSON reader and the underlying {@link java.io.Reader}. */ + @Override public void close() { peeked = PEEKED_NONE; stack[0] = JsonScope.CLOSED; @@ -1180,11 +1194,7 @@ public final class JsonReaderEx implements Closeable { push(JsonScope.EMPTY_OBJECT); count++; } - else if (p == PEEKED_END_ARRAY) { - stackSize--; - count--; - } - else if (p == PEEKED_END_OBJECT) { + else if (p == PEEKED_END_ARRAY || p == PEEKED_END_OBJECT) { stackSize--; count--; } diff --git a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java index 8016b9b59539..6e7d21dee963 100644 --- a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java +++ b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java @@ -1,7 +1,6 @@ // Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - package org.jetbrains.jsonProtocol; import java.lang.annotation.ElementType; diff --git a/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml b/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml index d809f8c5132e..f8259f8992b9 100644 --- a/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml +++ b/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml @@ -1,6 +1,6 @@ - + @@ -10,6 +10,6 @@ + - - + \ No newline at end of file diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/AbsentSubtypeAspect.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/AbsentSubtypeAspect.java deleted file mode 100644 index 4a3b18df1d0e..000000000000 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/AbsentSubtypeAspect.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.jetbrains.protocolReader; - -class AbsentSubtypeAspect extends SubtypeAspect { - - @Override - void writeGetSuperMethodJava(TextOutput out) { - } - - @Override - void writeSuperFieldJava(TextOutput out) { - } - - @Override - void writeSuperConstructorParamJava(TextOutput out) { - } - - @Override - void writeSuperConstructorInitialization(TextOutput out) { - } - - @Override - void writeParseMethod(String className, ClassScope scope, TextOutput out) { - } - - @Override - public void writeInstantiateCode(String className, TextOutput out) { - out.append("new ").append(className); - } -} diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java index 3485c83e684f..bd4b5f332ada 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java @@ -1,10 +1,11 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - package org.jetbrains.protocolReader; -import java.util.*; +import gnu.trove.THashMap; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; public class DynamicReader { final LinkedHashMap, TypeHandler> typeToTypeHandler; @@ -15,20 +16,20 @@ public class DynamicReader { root = new ReaderRoot<>(readerRootClass, typeToTypeHandler); } - public GeneratedCodeMap generateStaticReader(StringBuilder stringBuilder, String packageName, String className, - Collection basePackages) { - final GlobalScope globalScope = new GlobalScope(typeToTypeHandler.values(), basePackages); + @NotNull + public GeneratedCodeMap generateReader(StringBuilder stringBuilder, String packageName, String className, + Collection basePackages) { + GlobalScope globalScope = new GlobalScope(typeToTypeHandler.values(), basePackages); FileScope fileScope = globalScope.newFileScope(stringBuilder); - final TextOutput out = fileScope.getOutput(); + TextOutput out = fileScope.getOutput(); out.append("// Generated source"); out.newLine().append("package ").append(packageName).append(';'); out.newLine().newLine().append("import org.jetbrains.jsonProtocol.*;"); out.newLine().newLine().append("import static org.jetbrains.jsonProtocol.JsonReaders.*;"); out.newLine().newLine().append("public final class ").append(className).space(); - out.append(root.getType().isInterface() ? "implements" : "extends").space().append(root.getType().getCanonicalName()).openBlock( - false); + out.append(root.getType().isInterface() ? "implements" : "extends").space().append(root.getType().getCanonicalName()).openBlock(false); - final ClassScope rootClassScope = fileScope.newClassScope(); + ClassScope rootClassScope = fileScope.newClassScope(); root.writeStaticMethodJava(rootClassScope); for (TypeHandler typeHandler : typeToTypeHandler.values()) { @@ -37,27 +38,31 @@ public class DynamicReader { out.newLine(); } + boolean isFirst = true; for (TypeHandler typeHandler : globalScope.getTypeFactories()) { - String name = globalScope.getTypeImplShortName(typeHandler); + if (isFirst) { + isFirst = false; + } + else { + out.newLine(); + } + String originName = typeHandler.getTypeClass().getCanonicalName(); - out.newLine().append("static final class ").append(name).append(Util.TYPE_FACTORY_NAME_POSTFIX).append(" extends ObjectFactory<"); + out.newLine().append("private static final class ").append(globalScope.getTypeImplShortName(typeHandler)).append(Util.TYPE_FACTORY_NAME_POSTFIX).append(" extends ObjectFactory<"); out.append(originName).append('>').openBlock(); out.append("@Override").newLine().append("public ").append(originName).append(" read(").append(Util.JSON_READER_PARAMETER_DEF); out.append(')').openBlock(); out.append("return "); typeHandler.writeInstantiateCode(rootClassScope, out); - out.append('(').append(Util.READER_NAME).append(");").closeBlock(); + out.append('(').append(Util.READER_NAME).append(", null);").closeBlock(); out.closeBlock(); - out.newLine(); } out.closeBlock(); - Map, String> typeToImplClassName = new HashMap<>(); + Map, String> typeToImplClassName = new THashMap<>(); for (TypeHandler typeHandler : typeToTypeHandler.values()) { - String shortName = fileScope.getTypeImplShortName(typeHandler); - String fullReference = packageName + "." + className + "." + shortName; - typeToImplClassName.put(typeHandler.getTypeClass(), fullReference); + typeToImplClassName.put(typeHandler.getTypeClass(), packageName + "." + className + "." + fileScope.getTypeImplShortName(typeHandler)); } return new GeneratedCodeMap(typeToImplClassName); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java index 4e79fb71498d..326d3f9a1c81 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java @@ -1,6 +1,6 @@ package org.jetbrains.protocolReader; -class ExistingSubtypeAspect extends SubtypeAspect { +class ExistingSubtypeAspect { private SubtypeCaster subtypeCaster; private final TypeRef jsonSuperClass; @@ -12,28 +12,23 @@ class ExistingSubtypeAspect extends SubtypeAspect { this.subtypeCaster = subtypeCaster; } - @Override void writeGetSuperMethodJava(TextOutput out) { out.newLine().append("@Override").newLine().append("public ").append(jsonSuperClass.get().getTypeClass().getCanonicalName() ).append(" getSuper()").openBlock(); out.append("return ").append(Util.BASE_VALUE_PREFIX).semi().closeBlock(); } - @Override void writeSuperFieldJava(TextOutput out) { out.newLine().append("private final ").append(jsonSuperClass.get().getTypeClass().getCanonicalName()).append(' ').append(Util.BASE_VALUE_PREFIX).semi().newLine(); } - @Override void writeSuperConstructorParamJava(TextOutput out) { out.comma().append(jsonSuperClass.get().getTypeClass().getCanonicalName()).append(' ').append(Util.BASE_VALUE_PREFIX); } - @Override void writeSuperConstructorInitialization(TextOutput out) { out.append("this.").append(Util.BASE_VALUE_PREFIX).append(" = ").append(Util.BASE_VALUE_PREFIX).append(';').newLine().newLine(); } - @Override void writeParseMethod(String className, ClassScope scope, TextOutput out) { out.newLine().append("public static ").append(className).space().append("parse").append("(").append(Util.JSON_READER_PARAMETER_DEF).append(')').openBlock(); out.append("return "); @@ -44,7 +39,6 @@ class ExistingSubtypeAspect extends SubtypeAspect { out.newLine(); } - @Override public void writeInstantiateCode(String className, TextOutput out) { out.append(className).append(".parse"); } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java index 111e58caa3a6..77a91e8543d1 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java @@ -1,5 +1,6 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; import org.jetbrains.jsonProtocol.JsonField; import org.jetbrains.jsonProtocol.JsonNullable; import org.jetbrains.jsonProtocol.JsonOptionalField; @@ -28,7 +29,7 @@ class FieldProcessor { // todo sort by source location Arrays.sort(methods, new Comparator() { @Override - public int compare(Method o1, Method o2) { + public int compare(@NotNull Method o1, @NotNull Method o2) { return o1.getName().compareTo(o2.getName()); } }); @@ -120,20 +121,10 @@ class FieldProcessor { int position = volatileFields.size(); FieldTypeInfo fieldTypeInfo; if (internalType) { - fieldTypeInfo = new FieldTypeInfo() { - @Override - public void appendValueTypeNameJava(FileScope scope, TextOutput out) { - fieldTypeParser.appendInternalValueTypeName(scope, out); - } - }; + fieldTypeInfo = fieldTypeParser::appendInternalValueTypeName; } else { - fieldTypeInfo = new FieldTypeInfo() { - @Override - public void appendValueTypeNameJava(FileScope scope, TextOutput out) { - fieldTypeParser.appendFinishedValueTypeName(out); - } - }; + fieldTypeInfo = (scope, out) -> fieldTypeParser.appendFinishedValueTypeName(out); } VolatileFieldBinding binding = new VolatileFieldBinding(position, fieldTypeInfo); volatileFields.add(binding); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java index 6a31b5ad59c0..9866d7b71d01 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java @@ -2,6 +2,7 @@ package org.jetbrains.protocolReader; import gnu.trove.THashMap; import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; import java.util.*; @@ -84,7 +85,7 @@ public class GlobalScope { // Sort to produce consistent GeneratedCodeMap later. Collections.sort(list, new Comparator>() { @Override - public int compare(TypeHandler o1, TypeHandler o2) { + public int compare(@NotNull TypeHandler o1, @NotNull TypeHandler o2) { return getName(o1).compareTo(getName(o2)); } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java index cc4e2566f4dd..a02b4ae8f18a 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java @@ -117,7 +117,10 @@ class InterfaceReader { } for (SubtypeCaster subtypeCaster : subtypeCasters) { - subtypeCaster.getSubtypeHandler().getSubtypeSupport().setSubtypeCaster(subtypeCaster); + ExistingSubtypeAspect subtypeSupport = subtypeCaster.getSubtypeHandler().getSubtypeSupport(); + if (subtypeSupport != null) { + subtypeSupport.setSubtypeCaster(subtypeCaster); + } } return typeToTypeHandler; diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java index adf5ac6f7ddf..a877b654c020 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java @@ -4,19 +4,22 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; + import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.Collections; -import java.util.Iterator; +import java.util.List; abstract class MethodHandler { abstract void writeMethodImplementationJava(ClassScope classScope, Method m, TextOutput out); - protected static void appendMethodSignatureJava(Method m, Iterable paramNames, TextOutput out) { + protected static void appendMethodSignatureJava(@NotNull Method m, @NotNull List paramNames, @NotNull TextOutput out) { out.append(m.getName()).append('('); boolean firstArg = true; - Iterator namesIt = paramNames.iterator(); - for (Type arg : m.getGenericParameterTypes()) { + Type[] types = m.getGenericParameterTypes(); + for (int i = 0, length = types.length; i < length; i++) { + Type arg = types[i]; if (firstArg) { firstArg = false; } @@ -24,7 +27,7 @@ abstract class MethodHandler { out.comma(); } Util.writeJavaTypeName(arg, out); - out.append(' ').append(namesIt.next()); + out.space().append(paramNames.get(i)); } out.append(')'); } @@ -33,10 +36,10 @@ abstract class MethodHandler { writeMethodDeclarationJava(out, m, Collections.emptyList()); } - protected static void writeMethodDeclarationJava(TextOutput out, Method m, Iterable paramNames) { + protected static void writeMethodDeclarationJava(@NotNull TextOutput out, @NotNull Method m, @NotNull List paramNames) { out.append("@Override").newLine().append("public "); Util.writeJavaTypeName(m.getGenericReturnType(), out); - out.append(' '); + out.space(); appendMethodSignatureJava(m, paramNames, out); } } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java index 025fb525c367..d6e4275ae0e3 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java @@ -43,7 +43,7 @@ class ObjectValueReader extends ValueReader { refToType.get().writeInstantiateCode(scope.getRootClassScope(), subtyping, out); out.append('('); addReaderParameter(subtyping, out); - if (subtyping && refToType.get().getSubtypeSupport() instanceof ExistingSubtypeAspect) { + if (subtyping && refToType.get().getSubtypeSupport() != null) { out.comma().append("this"); } out.append(')'); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java index fade272204a5..56dcc310fa83 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java @@ -1,22 +1,30 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; + import java.lang.reflect.Method; +import java.util.Arrays; import java.util.Collections; import java.util.List; class ReadDelegate { private static final List STATIC_METHOD_PARAM_NAME_LIST = Collections.singletonList(Util.READER_NAME); + private static final List STATIC_METHOD_PARAM_NAME_LIST2 = Arrays.asList(Util.READER_NAME, "nextName"); private final TypeHandler typeHandler; private final boolean isList; - ReadDelegate(TypeHandler typeHandler, boolean isList) { + private final List paramNames; + + ReadDelegate(@NotNull TypeHandler typeHandler, boolean isList, boolean hasNextNameParam) { this.typeHandler = typeHandler; this.isList = isList; + + paramNames = hasNextNameParam ? STATIC_METHOD_PARAM_NAME_LIST2 : STATIC_METHOD_PARAM_NAME_LIST; } void write(ClassScope scope, Method method, TextOutput out) { - MethodHandler.writeMethodDeclarationJava(out, method, STATIC_METHOD_PARAM_NAME_LIST); + MethodHandler.writeMethodDeclarationJava(out, method, paramNames); out.openBlock(); out.append("return "); if (isList) { @@ -24,7 +32,10 @@ class ReadDelegate { } else { typeHandler.writeInstantiateCode(scope, out); - out.append("(").append(Util.READER_NAME).append(')'); + out.append('(').append(Util.READER_NAME); + out.comma().space(); + out.append(paramNames.size() == 1 ? "null" : "nextName"); + out.append(')'); } out.semi(); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java index 6988139a5bcb..8299afe91ece 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java @@ -18,7 +18,7 @@ public class ReaderGenerator { configuration.getPackageName().replace('.', File.separatorChar), configuration.getClassName() + ".java")); - generateImpl(configuration, fileUpdater.builder); + generate(configuration, fileUpdater.builder); fileUpdater.update(); } @@ -96,12 +96,7 @@ public class ReaderGenerator { } } - return new Params() { - @Override - public String outputDirectory() { - return outputDirParam.getValue(); - } - }; + return outputDirParam::getValue; } private interface ParamListener { @@ -128,12 +123,12 @@ public class ReaderGenerator { } protected static GeneratedCodeMap buildParserMap(GenerateConfiguration configuration) { - return generateImpl(configuration, new StringBuilder()); + return generate(configuration, new StringBuilder()); } - private static GeneratedCodeMap generateImpl(GenerateConfiguration configuration, StringBuilder stringBuilder) { - return configuration.getParser().generateStaticReader(stringBuilder, - configuration.getPackageName(), configuration.getClassName(), - configuration.getBasePackagesMap()); + private static GeneratedCodeMap generate(GenerateConfiguration configuration, StringBuilder stringBuilder) { + return configuration.getParser().generateReader(stringBuilder, + configuration.getPackageName(), configuration.getClassName(), + configuration.getBasePackagesMap()); } } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java index 7914a5103ac6..f7ce9eb9eb39 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java @@ -1,7 +1,8 @@ package org.jetbrains.protocolReader; -import org.jetbrains.io.JsonReaderEx; import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.io.JsonReaderEx; import org.jetbrains.jsonProtocol.JsonParseMethod; import java.lang.reflect.Method; @@ -32,7 +33,7 @@ class ReaderRoot { Method[] methods = clazz.getMethods(); Arrays.sort(methods, new Comparator() { @Override - public int compare(Method o1, Method o2) { + public int compare(@NotNull Method o1, @NotNull Method o2) { return o1.getName().compareTo(o2.getName()); } }); @@ -68,12 +69,12 @@ class ReaderRoot { } Type[] arguments = m.getGenericParameterTypes(); - if (arguments.length != 1) { + if (arguments.length > 2) { throw new JsonProtocolModelParseException("Exactly one argument is expected in " + m); } Type argument = arguments[0]; if (argument == JsonReaderEx.class || argument == Object.class) { - methodMap.put(m, new ReadDelegate(typeHandler, isList)); + methodMap.put(m, new ReadDelegate(typeHandler, isList, arguments.length != 1)); } else { throw new JsonProtocolModelParseException("Unrecognized argument type in " + m); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/SubtypeAspect.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/SubtypeAspect.java deleted file mode 100644 index 9af37de01e55..000000000000 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/SubtypeAspect.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.jetbrains.protocolReader; - -/** - * Encapsulate subtype aspects of the type. - */ -abstract class SubtypeAspect { - abstract void writeSuperFieldJava(TextOutput out); - abstract void writeSuperConstructorParamJava(TextOutput out); - abstract void writeSuperConstructorInitialization(TextOutput out); - - abstract void writeParseMethod(String className, ClassScope scope, TextOutput out); - - public abstract void writeInstantiateCode(String className, TextOutput out); - - abstract void writeGetSuperMethodJava(TextOutput out); - - public void setSubtypeCaster(SubtypeCaster subtypeCaster) { - } -} \ No newline at end of file diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java index 401fbcff79d0..a2aaf4424429 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java @@ -1,9 +1,7 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jsonProtocol.JsonObjectBased; import java.lang.reflect.Method; @@ -16,14 +14,13 @@ class TypeHandler { private final List volatileFields; - /** Method implementation for dynamic proxy. */ private final LinkedHashMap methodHandlerMap; /** Loaders that should read values and save them in field array on parse time. */ private final List fieldLoaders; /** Subtype aspects of the type or null */ - private final SubtypeAspect subtypeAspect; + private final ExistingSubtypeAspect subtypeAspect; private final boolean hasLazyFields; @@ -37,29 +34,25 @@ class TypeHandler { this.methodHandlerMap = methodHandlerMap; this.fieldLoaders = fieldLoaders; this.hasLazyFields = hasLazyFields; - if (jsonSuperClass == null) { - subtypeAspect = new AbsentSubtypeAspect(); - } - else { - subtypeAspect = new ExistingSubtypeAspect(jsonSuperClass); - } + subtypeAspect = jsonSuperClass == null ? null : new ExistingSubtypeAspect(jsonSuperClass); } public Class getTypeClass() { return typeClass; } - public SubtypeAspect getSubtypeSupport() { + @Nullable + public ExistingSubtypeAspect getSubtypeSupport() { return subtypeAspect; } - public void writeInstantiateCode(ClassScope scope, TextOutput out) { + public void writeInstantiateCode(@NotNull ClassScope scope, @NotNull TextOutput out) { writeInstantiateCode(scope, false, out); } - public void writeInstantiateCode(ClassScope scope, boolean deferredReading, TextOutput out) { + public void writeInstantiateCode(@NotNull ClassScope scope, boolean deferredReading, @NotNull TextOutput out) { String className = scope.getTypeImplReference(this); - if (deferredReading) { + if (deferredReading || subtypeAspect == null) { out.append("new ").append(className); } else { @@ -67,10 +60,10 @@ class TypeHandler { } } - public void writeStaticClassJava(FileScope fileScope) { + public void writeStaticClassJava(@NotNull FileScope fileScope) { TextOutput out = fileScope.getOutput(); String valueImplClassName = fileScope.getTypeImplShortName(this); - out.append("public static final class ").append(valueImplClassName); + out.append("private static final class ").append(valueImplClassName); out.append(" implements ").append(getTypeClass().getCanonicalName()).openBlock(); @@ -89,12 +82,16 @@ class TypeHandler { out.newLine(); } - subtypeAspect.writeSuperFieldJava(out); + if (subtypeAspect != null) { + subtypeAspect.writeSuperFieldJava(out); + } writeConstructorMethod(valueImplClassName, classScope, out); out.newLine(); - subtypeAspect.writeParseMethod(valueImplClassName, classScope, out); + if (subtypeAspect != null) { + subtypeAspect.writeParseMethod(valueImplClassName, classScope, out); + } for (Map.Entry en : methodHandlerMap.entrySet()) { out.newLine(); @@ -103,7 +100,9 @@ class TypeHandler { } writeBaseMethods(out); - subtypeAspect.writeGetSuperMethodJava(out); + if (subtypeAspect != null) { + subtypeAspect.writeGetSuperMethodJava(out); + } out.indentOut().append('}'); } @@ -132,27 +131,47 @@ class TypeHandler { out.closeBlock(); } - private void writeConstructorMethod(String valueImplClassName, ClassScope classScope, TextOutput out) { - out.newLine().append("public ").append(valueImplClassName).append("(").append(Util.JSON_READER_PARAMETER_DEF); - subtypeAspect.writeSuperConstructorParamJava(out); + private void writeConstructorMethod(@NotNull String valueImplClassName, @NotNull ClassScope classScope, @NotNull TextOutput out) { + out.newLine().append(valueImplClassName).append('(').append(Util.JSON_READER_PARAMETER_DEF).comma().append("String name"); + if (subtypeAspect != null) { + subtypeAspect.writeSuperConstructorParamJava(out); + } out.append(')').openBlock(); - subtypeAspect.writeSuperConstructorInitialization(out); + if (subtypeAspect != null) { + subtypeAspect.writeSuperConstructorInitialization(out); + } if (JsonObjectBased.class.isAssignableFrom(typeClass) || hasLazyFields) { - out.append(Util.PENDING_INPUT_READER_NAME).append(" = ").append(Util.READER_NAME).append(".subReader();").newLine(); + out.append(Util.PENDING_INPUT_READER_NAME).append(" = ").append(Util.READER_NAME).append(".subReader()").semi().newLine(); } if (fieldLoaders.isEmpty()) { out.append(Util.READER_NAME).append(".skipValue()").semi(); } else { - out.append(Util.READER_NAME).append(".beginObject();"); + out.append("if (name == null)").openBlock(); + { + out.append("reader.beginObject()").semi(); + out.newLine().append("if (reader.hasNext())").openBlock(); + { + out.append("name = reader.nextName()").semi(); + } + out.closeBlock(); + out.newLine().append("else").openBlock(); + { + out.append("return").semi(); + } + out.closeBlock(); + } + out.closeBlock(); + out.newLine(); + writeReadFields(out, classScope); // we don't read all data if we have lazy fields, so, we should not check end of stream //if (!hasLazyFields) { - out.newLine().append(Util.READER_NAME).append(".endObject();"); + out.newLine().newLine().append(Util.READER_NAME).append(".endObject()").semi(); //} } out.closeBlock(); @@ -166,16 +185,16 @@ class TypeHandler { out.newLine().append("int i = 0").semi(); } - out.newLine().append("while (reader.hasNext())").openBlock(!hasOnlyOneFieldLoader); - if (!hasOnlyOneFieldLoader) { - out.append("CharSequence name = reader.nextNameAsCharSequence();"); - } - + out.newLine().append("do").openBlock(); boolean isFirst = true; String operator = "if"; for (FieldLoader fieldLoader : fieldLoaders) { + if (!isFirst) { + out.newLine(); + } + String fieldName = fieldLoader.getFieldName(); - out.newLine().append(operator).append(" (").append(hasOnlyOneFieldLoader ? "reader.nextName()" : "name"); + out.append(operator).append(" (").append(hasOnlyOneFieldLoader ? "reader.nextName()" : "name"); out.append(".equals(\"").append(fieldName).append("\"))").openBlock(); { assignField(out, fieldName); @@ -204,6 +223,7 @@ class TypeHandler { out.newLine().append("else").openBlock().append("i++").semi().closeBlock(); } out.closeBlock(); + out.newLine().append("while ((name = reader.nextNameOrNull()) != null)").semi(); } private static TextOutput assignField(TextOutput out, String fieldName) { diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java index 105cd6665b2e..13c7fd1c39e0 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java @@ -1,5 +1,7 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; + import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.WildcardType; @@ -14,12 +16,12 @@ public class Util { public static final String BASE_VALUE_PREFIX = "baseMessage"; public static final String JSON_READER_CLASS_NAME = "org.jetbrains.io.JsonReaderEx"; - public static final String JSON_READER_PARAMETER_DEF = JSON_READER_CLASS_NAME + " " + READER_NAME; + public static final String JSON_READER_PARAMETER_DEF = JSON_READER_CLASS_NAME + ' ' + READER_NAME; /** * Generate Java type name of the passed type. Type may be parameterized. */ - public static void writeJavaTypeName(Type arg, TextOutput out) { + public static void writeJavaTypeName(@NotNull Type arg, @NotNull TextOutput out) { if (arg instanceof Class) { out.append(((Class)arg).getCanonicalName()); }