diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java index 1fa65263de27..86c87a7af046 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java @@ -20,9 +20,9 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.UnorderedPair; import com.intellij.psi.JavaTokenType; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; -import gnu.trove.THashSet; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -56,32 +56,25 @@ class StateMerger { for (DfaMemoryStateImpl state : ContainerUtil.concat(statesByFact.get(fact), statesWithNegations)) { statesByUnrelatedFacts.putValue(getUnrelatedFacts(fact, state), state); } - - Set removedStates = ContainerUtil.newIdentityTroveSet(); - List result = ContainerUtil.newArrayList(); + + Replacements replacements = new Replacements(states); for (Set key : statesByUnrelatedFacts.keySet()) { - Collection group = statesByUnrelatedFacts.get(key); - if (group.size() > 1) { - DfaMemoryStateImpl copy = group.iterator().next().createCopy(); - fact.removeFromState(copy); - if (fact.myType == FactType.equality) { - restoreOtherInequalities(fact, group, copy); + final Collection group = statesByUnrelatedFacts.get(key); + final Set unknowns = getAllUnknownVariables(group); + replacements.stripAndMerge(group, new Function() { + @Override + public DfaMemoryStateImpl fun(DfaMemoryStateImpl original) { + DfaMemoryStateImpl copy = withUnknownVariables(original, unknowns); + fact.removeFromState(copy); + if (fact.myType == FactType.equality) { + restoreOtherInequalities(fact, group, copy); + } + return copy; } - mergeUnknowns(copy, group); - - removedStates.addAll(group); - result.add(copy); - } + }); } - if (!result.isEmpty()) { - for (DfaMemoryStateImpl state : states) { - if (!removedStates.contains(state)) { - result.add(state); - } - } - return result; - } + if (replacements.hasMerges()) return replacements.getMergeResult(); } return null; } @@ -129,26 +122,20 @@ class StateMerger { return otherInequalities; } - private static void mergeUnknowns(DfaMemoryStateImpl mergedState, Collection complementaryStates) { - for (DfaMemoryStateImpl removedState : complementaryStates) { - for (DfaVariableValue unknownVar : removedState.getUnknownVariables()) { - mergedState.doFlush(unknownVar, true); - } + private static Set getAllUnknownVariables(Collection complementary) { + final Set toFlush = ContainerUtil.newLinkedHashSet(); + for (DfaMemoryStateImpl removedState : complementary) { + toFlush.addAll(removedState.getUnknownVariables()); } + return toFlush; } - private static List getMergeResult(List statesBeforeMerge, - final THashSet mergedStates, - DfaMemoryStateImpl mergeResult) { - List result = ContainerUtil.newArrayList(); - result.add(mergeResult); - result.addAll(ContainerUtil.filter(statesBeforeMerge, new Condition() { - @Override - public boolean value(DfaMemoryStateImpl state) { - return !mergedStates.contains(state); - } - })); - return result; + private static DfaMemoryStateImpl withUnknownVariables(DfaMemoryStateImpl original, Set toFlush) { + DfaMemoryStateImpl copy = original.createCopy(); + for (DfaVariableValue value : toFlush) { + copy.doFlush(value, true); + } + return copy; } @Nullable @@ -159,6 +146,7 @@ class StateMerger { byHash.putValue(state.getPartialHashCode(false, true), state); } + Replacements replacements = new Replacements(states); for (Integer key : byHash.keySet()) { Collection similarStates = byHash.get(key); if (similarStates.size() < 2) continue; @@ -171,16 +159,11 @@ class StateMerger { return state1.equalsByRelations(state2) && state1.equalsByVariableStates(state2); } }); - if (complementary.size() > 1) { - DfaMemoryStateImpl copy = state1.createCopy(); - mergeUnknowns(copy, complementary); - return getMergeResult(states, ContainerUtil.newIdentityTroveSet(complementary), copy); - } + if (mergeUnknowns(replacements, complementary)) break; } - } - return null; + return replacements.getMergeResult(); } @Nullable @@ -191,10 +174,12 @@ class StateMerger { byHash.putValue(state.getPartialHashCode(false, false), state); } + Replacements replacements = new Replacements(states); for (Integer key : byHash.keySet()) { Collection similarStates = byHash.get(key); if (similarStates.size() < 2) continue; + groupLoop: for (final DfaMemoryStateImpl state1 : similarStates) { ProgressManager.checkCanceled(); for (final DfaVariableValue var : state1.getChangedVariables()) { @@ -205,25 +190,33 @@ class StateMerger { List complementary = ContainerUtil.filter(similarStates, new Condition() { @Override public boolean value(DfaMemoryStateImpl state2) { - return state1.equalsByRelations(state2) && + return state1.equalsByRelations(state2) && areEquivalentModuloVar(state1, state2, var) && areVarStatesEqualModuloNullability(state1, state2, var); } }); - if (complementary.size() > 1) { - DfaMemoryStateImpl copy = state1.createCopy(); - mergeUnknowns(copy, complementary); - return getMergeResult(states, ContainerUtil.newIdentityTroveSet(complementary), copy); - } + if (mergeUnknowns(replacements, complementary)) break groupLoop; } - } - } - return null; + return replacements.getMergeResult(); } - + + private static boolean mergeUnknowns(Replacements replacements, List complementary) { + if (complementary.size() < 2) return false; + + final Set toFlush = getAllUnknownVariables(complementary); + if (toFlush.isEmpty()) return false; + + return replacements.stripAndMerge(complementary, new Function() { + @Override + public DfaMemoryStateImpl fun(DfaMemoryStateImpl original) { + return withUnknownVariables(original, toFlush); + } + }); + } + private boolean areEquivalentModuloVar(DfaMemoryStateImpl state1, DfaMemoryStateImpl state2, DfaVariableValue var) { DfaMemoryStateImpl copy1 = copyWithoutVar(state1, var); DfaMemoryStateImpl copy2 = copyWithoutVar(state2, var); @@ -380,4 +373,51 @@ class StateMerger { } } } + + private static class Replacements { + private final List myAllStates; + private final Set myRemovedStates = ContainerUtil.newIdentityTroveSet(); + private final List myMerged = ContainerUtil.newArrayList(); + + Replacements(List allStates) { + myAllStates = allStates; + } + + boolean hasMerges() { return !myMerged.isEmpty(); } + + @Nullable + List getMergeResult() { + if (hasMerges()) { + List result = ContainerUtil.newArrayList(myMerged); + for (DfaMemoryStateImpl state : myAllStates) { + if (!myRemovedStates.contains(state)) { + result.add(state); + } + } + return result; + } + return null; + } + + boolean stripAndMerge(Collection group, + Function stripper) { + if (group.size() <= 1) return false; + + boolean hasMerges = false; + MultiMap strippedToOriginals = MultiMap.create(); + for (DfaMemoryStateImpl original : group) { + strippedToOriginals.putValue(stripper.fun(original), original); + } + for (Map.Entry> entry : strippedToOriginals.entrySet()) { + Collection merged = entry.getValue(); + if (merged.size() > 1) { + myRemovedStates.addAll(merged); + myMerged.add(entry.getKey()); + hasMerges = true; + } + } + return hasMerges; + } + } + } diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java index 7d7d697d724e..18dbccb258c5 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java @@ -740,7 +740,11 @@ public class JavaDocInfoGenerator { if (inferred) buffer.append(""); final PsiClassType type = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createType(annotationType, PsiSubstitutor.EMPTY); buffer.append("@"); - generateType(buffer, type, owner, generateLink); + if (inferred && !generateLink) { + buffer.append(type.getPresentableText()); + } else { + generateType(buffer, type, owner, generateLink); + } final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); if (attributes.length > 0) { buffer.append("("); @@ -778,9 +782,11 @@ public class JavaDocInfoGenerator { } } else if (external) { if (inferred) buffer.append(""); - buffer.append(XmlStringUtil.escapeString(annotation.getText())); - buffer.append(" "); + String annoText = inferred ? "@" + annotation.getNameReferenceElement().getReferenceName() + annotation.getParameterList().getText() + : annotation.getText(); + buffer.append(XmlStringUtil.escapeString(annoText)); if (inferred) buffer.append(""); + buffer.append(" "); } else { buffer.append(""); diff --git a/java/java-tests/testData/codeInsight/completion/normal/DontCastPartiallyInstanceofedQualifier.java b/java/java-tests/testData/codeInsight/completion/normal/DontCastPartiallyInstanceofedQualifier.java new file mode 100644 index 000000000000..ce2b3df46e79 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/DontCastPartiallyInstanceofedQualifier.java @@ -0,0 +1,16 @@ +public abstract class Zzza { + + abstract Object getFoo(); + + void foo(Zzza other) { + int a; + if (other.getFoo() instanceof String) { + a = 1; + } else { + a = 2; + } + other.getFoo().subst + } + + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionDfaTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionDfaTest.groovy index 4c3cec03ce17..eaa0975f37d0 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionDfaTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionDfaTest.groovy @@ -34,6 +34,7 @@ class NormalCompletionDfaTest extends LightFixtureCompletionTestCase { void testCastTooComplexInstanceofedQualifier() { doAntiTest() } void testDontCastInstanceofedQualifier() { doTest(); } + void testDontCastPartiallyInstanceofedQualifier() { doAntiTest(); } void testQualifierCastingWithUnknownAssignments() { doTest(); } void testQualifierCastingBeforeLt() { doTest(); } void testCastQualifierForPrivateFieldReference() { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java index a12fbb51ddfb..b0f8ff27b8f8 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java @@ -132,7 +132,7 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC public void testInferredAnnoGutter() { setUpLibraries(); openDecompiledClass("org.apache.velocity.util.ExceptionUtils"); - checkHasGutter("@org.jetbrains.annotations.Contract("null,_,_->null")"); + checkHasGutter("@Contract("null,_,_->null")"); } public void testExternalAnnoGutter() { diff --git a/platform/core-api/src/com/intellij/lang/LanguageUtil.java b/platform/core-api/src/com/intellij/lang/LanguageUtil.java index 96dae6f63f34..6179acfabe7a 100644 --- a/platform/core-api/src/com/intellij/lang/LanguageUtil.java +++ b/platform/core-api/src/com/intellij/lang/LanguageUtil.java @@ -17,7 +17,9 @@ package com.intellij.lang; import com.intellij.lexer.Lexer; +import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -26,6 +28,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; @@ -74,7 +77,7 @@ public final class LanguageUtil { return language instanceof TemplateLanguage; } - public static boolean isInjectableLanguage(Language language) { + public static boolean isInjectableLanguage(@NotNull Language language) { if (language == Language.ANY) { return false; } @@ -93,6 +96,27 @@ public final class LanguageUtil { return true; } + public static boolean isFileLanguage(@NotNull Language language) { + if (language instanceof DependentLanguage || language instanceof InjectableLanguage) return false; + if (LanguageParserDefinitions.INSTANCE.forLanguage(language) == null) return false; + LanguageFileType type = language.getAssociatedFileType(); + if (type == null || StringUtil.isEmpty(type.getDefaultExtension())) return false; + String name = language.getDisplayName(); + if (StringUtil.isEmpty(name) || name.startsWith("<") || name.startsWith("[")) return false; + return StringUtil.isNotEmpty(type.getDefaultExtension()); + } + + @NotNull + public static List getFileLanguages() { + List result = ContainerUtil.newArrayList(); + for (Language language : Language.getRegisteredLanguages()) { + if (!isFileLanguage(language)) continue; + result.add(language); + } + Collections.sort(result, LANGUAGE_COMPARATOR); + return result; + } + @NotNull public static Language getRootLanguage(@NotNull PsiElement element) { final FileViewProvider provider = element.getContainingFile().getViewProvider(); diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/NewScratchFileAction.java b/platform/lang-impl/src/com/intellij/ide/scratch/NewScratchFileAction.java index 11c7ff2efe14..29320e24f9a4 100644 --- a/platform/lang-impl/src/com/intellij/ide/scratch/NewScratchFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/scratch/NewScratchFileAction.java @@ -16,9 +16,8 @@ package com.intellij.ide.scratch; import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.lang.DependentLanguage; -import com.intellij.lang.InjectableLanguage; import com.intellij.lang.Language; +import com.intellij.lang.LanguageUtil; import com.intellij.lang.StdLanguages; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -31,23 +30,18 @@ import com.intellij.openapi.ui.popup.ListPopup; import com.intellij.openapi.ui.popup.ListPopupStep; import com.intellij.openapi.ui.popup.PopupStep; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import com.intellij.util.ObjectUtils; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.ui.EmptyIcon; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.util.Comparator; import java.util.List; -import java.util.Set; /** * @author ignatov @@ -56,7 +50,7 @@ public class NewScratchFileAction extends AnAction implements DumbAware { public static final int MAX_VISIBLE_SIZE = 20; public NewScratchFileAction() { - super("New Scratch Pad...", null, null); + super("New Scratch File...", null, null); } @Override @@ -82,7 +76,7 @@ public class NewScratchFileAction extends AnAction implements DumbAware { @NotNull static ListPopup buildLanguagePopup(@Nullable Language previous, final Consumer onChoosen) { - List languages = getLanguages(); + List languages = LanguageUtil.getFileLanguages(); BaseListPopupStep step = new BaseListPopupStep("Choose Language", languages) { @NotNull @@ -128,30 +122,4 @@ public class NewScratchFileAction extends AnAction implements DumbAware { } return popup; } - - - @NotNull - private static List getLanguages() { - Set result = ContainerUtilRt.newTreeSet(new Comparator() { - @Override - public int compare(@NotNull Language l1, @NotNull Language l2) { - return l1.getDisplayName().compareTo(l2.getDisplayName()); - } - }); - for (Language lang : Language.getRegisteredLanguages()) { - if (!StringUtil.isEmpty(lang.getDisplayName())) result.add(lang); - for (Language dialect : lang.getDialects()) result.add(dialect); - } - return ContainerUtil.filter(result, new Condition() { - @Override - public boolean value(Language lang) { - if (lang instanceof DependentLanguage || lang instanceof InjectableLanguage) return false; - LanguageFileType type = lang.getAssociatedFileType(); - if (type == null) return false; - String name = lang.getDisplayName(); - if (StringUtil.startsWith(name, "<") || StringUtil.startsWith(name, "[") || StringUtil.isEmpty(name) || StringUtil.equalsIgnoreCase(name, "SQL")) return false; - return !StringUtil.isEmpty(type.getDefaultExtension()); - } - }); - } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchWidget.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchWidget.java index 8dbeb7200a77..9a455cad2e4a 100644 --- a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchWidget.java +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchWidget.java @@ -28,6 +28,7 @@ import com.intellij.openapi.wm.CustomStatusBarWidget; import com.intellij.openapi.wm.StatusBarWidget; import com.intellij.openapi.wm.impl.status.EditorBasedWidget; import com.intellij.openapi.wm.impl.status.TextPanel; +import com.intellij.psi.LanguageSubstitutors; import com.intellij.testFramework.LightVirtualFile; import com.intellij.ui.ClickListener; import com.intellij.ui.awt.RelativePoint; @@ -50,7 +51,7 @@ class ScratchWidget extends EditorBasedWidget implements CustomStatusBarWidget.M new ClickListener() { @Override public boolean onClick(@NotNull MouseEvent e, int clickCount) { - final Project project = getProject(); + Project project = getProject(); Editor editor = getEditor(); final LightVirtualFile selectedFile = getScratchFile(); if (project == null || editor == null || selectedFile == null) return false; @@ -58,7 +59,7 @@ class ScratchWidget extends EditorBasedWidget implements CustomStatusBarWidget.M ListPopup popup = NewScratchFileAction.buildLanguagePopup(selectedFile.getLanguage(), new Consumer() { @Override public void consume(Language language) { - selectedFile.setLanguage(language); + selectedFile.setLanguage(LanguageSubstitutors.INSTANCE.substituteLanguage(language, selectedFile, myProject)); FileContentUtilCore.reparseFiles(selectedFile); update(); } diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java index 5c3fa9143ae4..568e8c0cf7ef 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java @@ -29,14 +29,12 @@ import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.editor.impl.LineSet; import com.intellij.openapi.editor.impl.RangeMarkerTree; import com.intellij.openapi.fileTypes.FileTypes; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.Processor; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -52,7 +50,7 @@ import java.util.List; */ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, Disposable { - private static final String MY_PANEL_PROPERTY = "EditorTextFieldCellRenderer.MyEditorPanel"; + private static final Key MY_PANEL_PROPERTY = Key.create("EditorTextFieldCellRenderer.MyEditorPanel"); public EditorTextFieldCellRenderer(Disposable parent) { Disposer.register(parent, this); @@ -96,7 +94,7 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, @NotNull private MyPanel getEditorPanel(JTable table) { - MyPanel panel = (MyPanel)table.getClientProperty(MY_PANEL_PROPERTY); + MyPanel panel = UIUtil.getClientProperty(table, MY_PANEL_PROPERTY); if (panel != null) { EditorColorsScheme scheme = panel.myEditor.getColorsScheme(); if (scheme instanceof DelegateColorScheme) { diff --git a/plugins/git4idea/src/git4idea/ui/GitResetDialog.java b/plugins/git4idea/src/git4idea/ui/GitResetDialog.java index 6600ee256acd..6f98e4c0d224 100644 --- a/plugins/git4idea/src/git4idea/ui/GitResetDialog.java +++ b/plugins/git4idea/src/git4idea/ui/GitResetDialog.java @@ -22,6 +22,7 @@ import git4idea.commands.GitCommand; import git4idea.commands.GitLineHandler; import git4idea.i18n.GitBundle; import git4idea.util.GitUIUtil; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.List; @@ -101,6 +102,12 @@ public class GitResetDialog extends DialogWrapper { init(); } + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return myCommitTextField; + } + /** * Validate */