diff --git a/.idea/modules.xml b/.idea/modules.xml index 52a0244f3249..553b6854a1ac 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -41,6 +41,7 @@ + @@ -107,6 +108,7 @@ + diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index 75b46b1aa8ef..1985a382aaa9 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome includeTargets << new File("${guessHome(this)}/build/scripts/utils.gant") @@ -100,7 +115,11 @@ def layoutFull(String home, String targetDirectory, String patchedDescriptorDir dir("rt") { fileset(dir: "${home}/lib/rt", includesfile: "${home}/lib/rt/required_for_dist.txt") } - jar("util.jar") { module("util") } + + jar("util.jar") { + module("util") + module("util-rt") + } jar("openapi.jar") { openapiModules.each { module it} @@ -231,6 +250,9 @@ public def layoutCommunityPlugins(String home) { } layoutPlugin("git4idea") { + jar("git4idea-rt.jar") { + module("git4idea-rt") + } fileset(dir: "$home/plugins/git4idea/lib") { include(name: "trilead-ssh2.jar") } @@ -468,6 +490,7 @@ def reorder(String home, String targetDirectory) { classpath { pathelement(location: util.output) pathelement(location: "$home/lib/jna.jar") + pathelement(location: "$home/lib/trove4j.jar") } } } @@ -476,6 +499,7 @@ def reorder(String home, String targetDirectory) { def layout_core(String home, String target) { layout(target) { jar("intellij-core.jar") { + module("util-rt") module("util") module("core-api") module("core-impl") diff --git a/build/update.xml b/build/update.xml index 4bdc3584b15c..5372bd479360 100644 --- a/build/update.xml +++ b/build/update.xml @@ -49,8 +49,10 @@ + + diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index 0d7a54633fec..54efeb29a62a 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -154,23 +154,25 @@ public class CompileDriver { myGenerationCompilerModuleToOutputDirMap = new HashMap, Pair>(); - final LocalFileSystem lfs = LocalFileSystem.getInstance(); - final IntermediateOutputCompiler[] generatingCompilers = CompilerManager.getInstance(myProject).getCompilers(IntermediateOutputCompiler.class, myCompilerFilter); - final Module[] allModules = ModuleManager.getInstance(myProject).getModules(); - final CompilerConfiguration config = CompilerConfiguration.getInstance(project); - for (Module module : allModules) { - for (IntermediateOutputCompiler compiler : generatingCompilers) { - final VirtualFile productionOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, false)); - final VirtualFile testOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, true)); - final Pair pair = new Pair(compiler, module); - final Pair outputs = new Pair(productionOutput, testOutput); - myGenerationCompilerModuleToOutputDirMap.put(pair, outputs); - } - if (config.isAnnotationProcessorsEnabled()) { - if (config.isAnnotationProcessingEnabled(module)) { - final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module); - if (path != null) { - lookupVFile(lfs, path); // ensure the file is created and added to VFS + if (!useCompileServer()) { + final LocalFileSystem lfs = LocalFileSystem.getInstance(); + final IntermediateOutputCompiler[] generatingCompilers = CompilerManager.getInstance(myProject).getCompilers(IntermediateOutputCompiler.class, myCompilerFilter); + final Module[] allModules = ModuleManager.getInstance(myProject).getModules(); + final CompilerConfiguration config = CompilerConfiguration.getInstance(project); + for (Module module : allModules) { + for (IntermediateOutputCompiler compiler : generatingCompilers) { + final VirtualFile productionOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, false)); + final VirtualFile testOutput = lookupVFile(lfs, CompilerPaths.getGenerationOutputPath(compiler, module, true)); + final Pair pair = new Pair(compiler, module); + final Pair outputs = new Pair(productionOutput, testOutput); + myGenerationCompilerModuleToOutputDirMap.put(pair, outputs); + } + if (config.isAnnotationProcessorsEnabled()) { + if (config.isAnnotationProcessingEnabled(module)) { + final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module); + if (path != null) { + lookupVFile(lfs, path); // ensure the file is created and added to VFS + } } } } diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java index e93a68fed095..f719d740ee5f 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/compiler/ArtifactsCompilerInstance.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -305,7 +305,7 @@ public class ArtifactsCompilerInstance extends GenericCompilerInstance createPathsHashSet() { - return new THashSet(FileUtil.T_HASHING_STRATEGY); + return new THashSet(FileUtil.PATH_HASHING_STRATEGY); } @Override diff --git a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteWindow.java b/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteWindow.java index f14a38242e12..18a485dc18e3 100644 --- a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteWindow.java +++ b/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteWindow.java @@ -55,9 +55,11 @@ public class PaletteWindow extends JPanel implements DataProvider { private PaletteGroupHeader myLastFocusedGroup; @NonNls private static final String ourHelpID = "guiDesigner.uiTour.palette"; + private PaletteManager myPaletteManager; public PaletteWindow(Project project) { myProject = project; + myPaletteManager = PaletteManager.getInstance(myProject); myProviders = Extensions.getExtensions(PaletteItemProvider.EP_NAME, project); for(PaletteItemProvider provider: myProviders) { provider.addListener(myPropertyChangeListener); @@ -180,7 +182,7 @@ public class PaletteWindow extends JPanel implements DataProvider { group.getComponentList().clearSelection(); } ListSelectionEvent event = new ListSelectionEvent(this, -1, -1, false); - PaletteManager.getInstance(myProject).notifySelectionChanged(event); + myPaletteManager.notifySelectionChanged(event); } @Nullable public PaletteItem getActiveItem() { @@ -252,7 +254,7 @@ public class PaletteWindow extends JPanel implements DataProvider { break; } } - PaletteManager.getInstance(myProject).notifySelectionChanged(e); + myPaletteManager.notifySelectionChanged(e); } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectStructureElementRenderer.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectStructureElementRenderer.java index 06bb5ec7731b..54037ea58236 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectStructureElementRenderer.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectStructureElementRenderer.java @@ -53,8 +53,7 @@ class ProjectStructureElementRenderer extends ColoredTreeCellRenderer { setToolTipText(null); setFont(UIUtil.getTreeFont()); - SimpleTextAttributes textAttributes = - selected && hasFocus ? SimpleTextAttributes.SELECTED_SIMPLE_CELL_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES; + SimpleTextAttributes textAttributes = SimpleTextAttributes.REGULAR_ATTRIBUTES; if (node.isDisplayInBold()) { textAttributes = SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; } @@ -74,6 +73,13 @@ class ProjectStructureElementRenderer extends ColoredTreeCellRenderer { textAttributes = textAttributes.derive(style, foreground, null, waveColor); setToolTipText(problemsHolder.composeTooltipMessage()); } + + append(displayName, textAttributes); + String description = projectStructureElement.getDescription(); + if (description != null) { + append(" (" + description + ")", SimpleTextAttributes.GRAY_ATTRIBUTES, false); + } + return; } } append(displayName, textAttributes); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElement.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElement.java index f9e866962e79..fed82781265d 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElement.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/daemon/ProjectStructureElement.java @@ -18,6 +18,11 @@ public abstract class ProjectStructureElement { public abstract String getPresentableName(); + @Nullable + public String getDescription() { + return null; + } + public abstract String getTypeName(); public abstract String getId(); diff --git a/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileContainerImpl.java b/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileContainerImpl.java index 6299468b345b..331db279750b 100644 --- a/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileContainerImpl.java +++ b/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileContainerImpl.java @@ -16,10 +16,11 @@ package com.intellij.util.descriptors.impl; +import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.MultiValuesMap; import com.intellij.openapi.vfs.*; -import com.intellij.openapi.Disposable; import com.intellij.util.EventDispatcher; import com.intellij.util.descriptors.*; import org.jetbrains.annotations.Nullable; @@ -135,6 +136,7 @@ public class ConfigFileContainerImpl implements ConfigFileContainer { } for (ConfigFileInfo configuration : newDescriptors) { final ConfigFileImpl configFile = new ConfigFileImpl(this, configuration); + Disposer.register(this, configFile); myConfigFiles.put(metaData, configFile); added.add(configFile); } @@ -142,6 +144,7 @@ public class ConfigFileContainerImpl implements ConfigFileContainer { for (ConfigFile descriptor : toDelete) { myConfigFiles.remove(descriptor.getMetaData(), descriptor); + Disposer.dispose(descriptor); } myCachedConfigFiles = null; diff --git a/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileImpl.java b/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileImpl.java index fcee66b35973..a64cc6c8a313 100644 --- a/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileImpl.java +++ b/java/idea-ui/src/com/intellij/util/descriptors/impl/ConfigFileImpl.java @@ -1,4 +1,3 @@ - package com.intellij.util.descriptors.impl; import com.intellij.openapi.project.Project; @@ -22,43 +21,38 @@ import org.jetbrains.annotations.Nullable; */ public class ConfigFileImpl implements ConfigFile { @NotNull private ConfigFileInfo myInfo; - private VirtualFilePointer myFilePointer; - private PsiFile myPsiFile; + private final VirtualFilePointer myFilePointer; + private volatile PsiFile myPsiFile; private final ConfigFileContainerImpl myContainer; private final Project myProject; private long myModificationCount; - private final Object myPsiFileLock = new Object(); - private final VirtualFilePointerListener myListener = new VirtualFilePointerListener() { - public void beforeValidityChanged(final VirtualFilePointer[] pointers) { - } - - public void validityChanged(final VirtualFilePointer[] pointers) { - synchronized (myPsiFileLock) { - myPsiFile = null; - } - onChange(); - } - }; public ConfigFileImpl(@NotNull final ConfigFileContainerImpl container, @NotNull final ConfigFileInfo configuration) { myContainer = container; myInfo = configuration; - setUrl(configuration.getUrl()); + final VirtualFilePointerManager pointerManager = VirtualFilePointerManager.getInstance(); + myFilePointer = pointerManager.create(configuration.getUrl(), this, new VirtualFilePointerListener() { + @Override + public void beforeValidityChanged(final VirtualFilePointer[] pointers) { + } + + @Override + public void validityChanged(final VirtualFilePointer[] pointers) { + myPsiFile = null; + onChange(); + } + }); + onChange(); Disposer.register(container, this); myProject = myContainer.getProject(); } - private void setUrl(String url) { - final VirtualFilePointerManager pointerManager = VirtualFilePointerManager.getInstance(); - myFilePointer = pointerManager.create(url, this, myListener); - onChange(); - } - private void onChange() { myModificationCount++; myContainer.fireDescriptorChanged(this); } + @Override public String getUrl() { return myFilePointer.getUrl(); } @@ -67,17 +61,16 @@ public class ConfigFileImpl implements ConfigFile { myInfo = info; } + @Override @Nullable public VirtualFile getVirtualFile() { return myFilePointer.getFile(); } + @Override @Nullable public PsiFile getPsiFile() { - PsiFile psiFile; - synchronized (myPsiFileLock) { - psiFile = myPsiFile; - } + PsiFile psiFile = myPsiFile; if (psiFile != null && psiFile.isValid()) { return psiFile; @@ -88,27 +81,29 @@ public class ConfigFileImpl implements ConfigFile { psiFile = PsiManager.getInstance(myProject).findFile(virtualFile); - synchronized (myPsiFileLock) { - myPsiFile = psiFile; - } + myPsiFile = psiFile; return psiFile; } + @Override @Nullable public XmlFile getXmlFile() { final PsiFile file = getPsiFile(); return file instanceof XmlFile ? (XmlFile)file : null; } + @Override public void dispose() { } + @Override @NotNull public ConfigFileInfo getInfo() { return myInfo; } + @Override public boolean isValid() { final PsiFile psiFile = getPsiFile(); if (psiFile == null || !psiFile.isValid()) { @@ -122,12 +117,14 @@ public class ConfigFileImpl implements ConfigFile { } + @Override @NotNull public ConfigFileMetaData getMetaData() { return myInfo.getMetaData(); } + @Override public long getModificationCount() { return myModificationCount; } diff --git a/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java b/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java index 083ff43a44db..8a042c1a6ae0 100644 --- a/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java +++ b/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java @@ -29,6 +29,8 @@ import com.intellij.util.ui.UIUtil; import javax.swing.*; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellEditor; import javax.swing.table.TableColumn; @@ -291,6 +293,7 @@ public class CodeStyleImportsPanel extends JPanel { PackageEntry entry = new PackageEntry(false,"", true); myImportLayoutList.insertEntryAt(entry, selected); refreshTableModel(selected, myImportLayoutTable); + updateButtons(); } private static void refreshTableModel(int selectedRow, JBTable table) { @@ -323,6 +326,7 @@ public class CodeStyleImportsPanel extends JPanel { AbstractTableModel model = (AbstractTableModel)myImportLayoutTable.getModel(); model.fireTableRowsInserted(selected, selected); myImportLayoutTable.setRowSelectionInterval(selected, selected); + updateButtons(); } private void removeEntryFromImportLayouts() { @@ -343,6 +347,7 @@ public class CodeStyleImportsPanel extends JPanel { if(selected >= 0) { myImportLayoutTable.setRowSelectionInterval(selected, selected); } + updateButtons(); } private void removeEntryFromPackages() { @@ -358,6 +363,7 @@ public class CodeStyleImportsPanel extends JPanel { if(selected >= 0) { myPackageTable.setRowSelectionInterval(selected, selected); } + updateButtons(); } private void moveRowUp() { @@ -374,6 +380,7 @@ public class CodeStyleImportsPanel extends JPanel { AbstractTableModel model = (AbstractTableModel)myImportLayoutTable.getModel(); model.fireTableRowsUpdated(selected-1, selected); myImportLayoutTable.setRowSelectionInterval(selected-1, selected-1); + updateButtons(); } private void moveRowDown() { @@ -390,6 +397,7 @@ public class CodeStyleImportsPanel extends JPanel { AbstractTableModel model = (AbstractTableModel)myImportLayoutTable.getModel(); model.fireTableRowsUpdated(selected, selected+1); myImportLayoutTable.setRowSelectionInterval(selected+1, selected+1); + updateButtons(); } private JBTable createTableForPackageEntries(final PackageEntryTable packageTable) { @@ -473,6 +481,12 @@ public class CodeStyleImportsPanel extends JPanel { final JBTable result = new JBTable(dataModel); result.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); resizeColumns(packageTable, result); + result.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + updateButtons(); + } + }); TableCellEditor editor = result.getDefaultEditor(String.class); if (editor instanceof DefaultCellEditor) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java index 1cb0667bd7e8..669905ed006e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java @@ -112,9 +112,11 @@ public class JavaNoVariantsDelegator extends CompletionContributor { PsiType type = JavaCompletionUtil.getLookupElementType(base); if (type != null && !PsiType.VOID.equals(type)) { PsiReferenceExpression ref = ReferenceExpressionCompletionContributor.createMockReference(position, type, base); - for (final LookupElement item : JavaSmartCompletionContributor.completeReference(position, ref, filter, true, true, parameters, - result.getPrefixMatcher())) { - qualifiedCollector.addElement(new JavaChainLookupElement(base, item)); + if (ref != null) { + for (final LookupElement item : JavaSmartCompletionContributor.completeReference(position, ref, filter, true, true, parameters, + result.getPrefixMatcher())) { + qualifiedCollector.addElement(new JavaChainLookupElement(base, item)); + } } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java index 5033f6a629cd..e1f28cd2b85a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java @@ -25,8 +25,8 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.patterns.PsiJavaPatterns; import com.intellij.patterns.PsiMethodPattern; +import com.intellij.patterns.StandardPatterns; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; @@ -46,7 +46,10 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; import static com.intellij.patterns.PsiJavaPatterns.psiElement; import static com.intellij.patterns.PsiJavaPatterns.psiMethod; @@ -57,7 +60,7 @@ import static com.intellij.patterns.PsiJavaPatterns.psiMethod; public class ReferenceExpressionCompletionContributor { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.ReferenceExpressionCompletionContributor"); private static final PsiMethodPattern OBJECT_METHOD_PATTERN = psiMethod().withName( - PsiJavaPatterns.string().oneOf("hashCode", "equals", "finalize", "wait", "notify", "notifyAll", "getClass", "clone", "toString")). + StandardPatterns.string().oneOf("hashCode", "equals", "finalize", "wait", "notify", "notifyAll", "getClass", "clone", "toString")). definedInClass(CommonClassNames.JAVA_LANG_OBJECT); private static final PrefixMatcher TRUE_MATCHER = new PrefixMatcher("") { @Override @@ -83,9 +86,9 @@ public class ReferenceExpressionCompletionContributor { } if (psiElement().inside( - PsiJavaPatterns.or( - psiElement(PsiAnnotationParameterList.class), - psiElement(PsiSwitchLabelStatement.class)) + StandardPatterns.or( + psiElement(PsiAnnotationParameterList.class), + psiElement(PsiSwitchLabelStatement.class)) ).accepts(element)) { return new ElementExtractorFilter(new AndFilter( new ClassFilter(PsiField.class), @@ -426,27 +429,37 @@ public class ReferenceExpressionCompletionContributor { PsiType qualifierType, final PsiType expectedType, JavaSmartCompletionParameters parameters) throws IncorrectOperationException { final PsiReferenceExpression mockRef = createMockReference(place, qualifierType, qualifierItem); + if (mockRef == null) { + return; + } final ElementFilter filter = getReferenceFilter(place, true); for (final LookupElement item : completeFinalReference(place, mockRef, filter, parameters)) { - if (shoudChain(place, qualifierType, expectedType, item)) { + if (shouldChain(place, qualifierType, expectedType, item)) { result.consume(new JavaChainLookupElement(qualifierItem, item)); } } } + @Nullable public static PsiReferenceExpression createMockReference(final PsiElement place, @NotNull PsiType qualifierType, LookupElement qualifierItem) { PsiElementFactory factory = JavaPsiFacade.getElementFactory(place.getProject()); if (qualifierItem.getObject() instanceof PsiClass) { - return (PsiReferenceExpression)factory - .createExpressionFromText(((PsiClass)qualifierItem.getObject()).getQualifiedName() + ".xxx", place); + try { + return (PsiReferenceExpression)factory + .createExpressionFromText(((PsiClass)qualifierItem.getObject()).getQualifiedName() + ".xxx", place); + } + catch (IncorrectOperationException e) { + LOG.info(e); + return null; + } } return (PsiReferenceExpression) factory.createExpressionFromText("xxx.xxx", JavaCompletionUtil .createContextWithXxxVariable(place, qualifierType)); } - private static boolean shoudChain(PsiElement element, PsiType qualifierType, PsiType expectedType, LookupElement item) { + private static boolean shouldChain(PsiElement element, PsiType qualifierType, PsiType expectedType, LookupElement item) { if (item.getObject() instanceof PsiMethod) { final PsiMethod method = (PsiMethod)item.getObject(); if (psiMethod().withName("toArray").withParameterCount(1) diff --git a/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java b/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java index ba8fffebe15c..5ab99de764ed 100644 --- a/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java +++ b/java/java-impl/src/com/intellij/psi/impl/JavaCodeBlockModificationListener.java @@ -20,6 +20,7 @@ import com.intellij.psi.*; import com.intellij.psi.impl.source.jsp.jspXml.JspDirective; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.xml.XmlFile; +import org.jetbrains.annotations.NotNull; public class JavaCodeBlockModificationListener implements PsiTreeChangePreprocessor { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.JavaCodeBlockModificationListener"); @@ -31,7 +32,7 @@ public class JavaCodeBlockModificationListener implements PsiTreeChangePreproces } @Override - public void treeChanged(final PsiTreeChangeEventImpl event) { + public void treeChanged(@NotNull final PsiTreeChangeEventImpl event) { switch (event.getCode()) { case BEFORE_CHILDREN_CHANGE: case BEFORE_PROPERTY_CHANGE: diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java index 31a4851df62c..d4dcd96dd43f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -272,7 +272,7 @@ public class PsiImplUtil { return new PsiImmediateClassType(classClass, substitutor); } - public static PsiAnnotation findAnnotation(@NotNull PsiAnnotationOwner modifierList, @NotNull String qualifiedName) { + @Nullable public static PsiAnnotation findAnnotation(@NotNull PsiAnnotationOwner modifierList, @NotNull String qualifiedName) { final String shortName = StringUtil.getShortName(qualifiedName); PsiAnnotation[] annotations = modifierList.getAnnotations(); for (PsiAnnotation annotation : annotations) { @@ -368,7 +368,7 @@ public class PsiImplUtil { } else if (member.hasModifierProperty(PsiModifier.PRIVATE)) { PsiClass topClass = PsiUtil.getTopLevelClass(member); - return topClass != null ? new LocalSearchScope(topClass) : new LocalSearchScope(file); + return topClass != null ? new LocalSearchScope(topClass) : file != null ? new LocalSearchScope(file) : maximalUseScope; } else { if (file instanceof PsiJavaFile) { @@ -388,7 +388,7 @@ public class PsiImplUtil { return getServerPageFile(element) != null; } - public static ServerPageFile getServerPageFile(final PsiElement element) { + @Nullable public static ServerPageFile getServerPageFile(final PsiElement element) { final PsiFile psiFile = PsiUtilCore.getTemplateLanguageFile(element); return psiFile instanceof ServerPageFile ? (ServerPageFile)psiFile : null; } diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java b/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java index d44097d038d4..962d7cb9256a 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/util/PsiScopesUtil.java @@ -144,7 +144,7 @@ public class PsiScopesUtil { public static boolean resolveAndWalk(PsiScopeProcessor processor, PsiJavaCodeReferenceElement ref, - PsiElement maxScope, + @Nullable PsiElement maxScope, boolean incompleteCode) { final PsiElement qualifier = ref.getQualifier(); final PsiElement classNameElement = ref.getReferenceNameElement(); diff --git a/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy b/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy index a996ce26aecf..3ad83a0f32bd 100644 --- a/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy +++ b/java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy @@ -17,7 +17,9 @@ package com.intellij.psi import com.intellij.openapi.application.ApplicationManager import com.intellij.psi.impl.source.PsiFileImpl +import com.intellij.psi.util.PsiTreeUtil import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import com.intellij.reference.SoftReference /** * @author peter @@ -30,13 +32,29 @@ class StubAstSwitchTest extends LightCodeInsightFixtureTestCase { def cls = ((PsiJavaFile)file).classes[0] assert file.stub + def oldCount = psiManager.modificationTracker.javaStructureModificationCount + ApplicationManager.application.runWriteAction { file.virtualFile.setBinaryContent(file.virtualFile.contentsToByteArray()) } assert file.stub - //todo - //either: assert !cls.valid - //or: assert cls == PsiTreeUtil.findElementOfClassAtOffset(file, 1, PsiClass, false) - //assert !file.stub + assert psiManager.modificationTracker.javaStructureModificationCount != oldCount + assert !cls.valid + assert cls != PsiTreeUtil.findElementOfClassAtOffset(file, 1, PsiClass, false) + assert !file.stub + } + + public void "test reachable psi classes remain valid when nothing changes"() { + int count = 1000 + List> classList = (0.. affectedBeforeDif = new HashSet(allAffectedFiles); + final ModulesBasedFileFilter moduleBasedFilter = new ModulesBasedFileFilter(context, chunk); final boolean incremental = globalMappings.differentiate( - delta, removedPaths, filesToCompile, allCompiledFiles, allAffectedFiles + delta, removedPaths, filesToCompile, allCompiledFiles, allAffectedFiles, moduleBasedFilter ); if (LOG.isDebugEnabled()) { @@ -103,13 +104,13 @@ public abstract class ModuleLevelBuilder extends Builder { if (!newlyAffectedFiles.isEmpty()) { - if (LOG.isDebugEnabled()) { - final List> wrongFiles = checkAffectedFilesInCorrectModules(context, chunk, newlyAffectedFiles); + final List> wrongFiles = checkAffectedFilesInCorrectModules(context, newlyAffectedFiles, moduleBasedFilter); if (!wrongFiles.isEmpty()) { LOG.debug("Wrong affected files for module chunk " + chunk.getName() + ": "); for (Pair pair : wrongFiles) { - LOG.debug("\t[" + pair.second.getName() + "] " + pair.first.getPath()); + final String name = pair.second != null? pair.second.getName() : "null"; + LOG.debug("\t[" + name + "] " + pair.first.getPath()); } } } @@ -146,45 +147,20 @@ public abstract class ModuleLevelBuilder extends Builder { } } - - private static List> checkAffectedFilesInCorrectModules(CompileContext context, ModuleChunk currentChunk, Collection affected) { + private static List> checkAffectedFilesInCorrectModules(CompileContext context, Collection affected, ModulesBasedFileFilter moduleBasedFilter) { if (affected.isEmpty()) { return Collections.emptyList(); } - - final Set chunkModules = currentChunk.getModules(); - final Map> cache = new HashMap>(); final List> result = new ArrayList>(); - for (File file : affected) { - final RootDescriptor moduleAndRoot = context.getModuleAndRoot(file); - if (moduleAndRoot == null) { - continue; + if (!moduleBasedFilter.accept(file)) { + final RootDescriptor moduleAndRoot = context.getModuleAndRoot(file); + result.add(Pair.create(file, moduleAndRoot != null? moduleAndRoot.module : null)); } - final Module moduleOfFile = moduleAndRoot.module; - if (chunkModules.contains(moduleOfFile)) { - continue; - } - Set moduleOfFileWithDependencies = cache.get(moduleOfFile); - if (moduleOfFileWithDependencies == null) { - moduleOfFileWithDependencies = ProjectPaths.getModulesWithDependentsRecursively(moduleOfFile, true); - cache.put(moduleOfFile, moduleOfFileWithDependencies); - } - if (intersects(moduleOfFileWithDependencies, chunkModules)) { - continue; - } - result.add(Pair.create(file, moduleOfFile)); } return result; } - private static boolean intersects(Set set1, Set set2) { - if (set1.size() < set2.size()) { - return new HashSet(set1).removeAll(set2); - } - return new HashSet(set2).removeAll(set1); - } - private static boolean chunkContainsAffectedFiles(CompileContext context, ModuleChunk chunk, final Set affected) throws IOException { final Set chunkModules = new HashSet(chunk.getModules()); if (!chunkModules.isEmpty()) { @@ -221,4 +197,40 @@ public abstract class ModuleLevelBuilder extends Builder { return removed != null? removed : Collections.emptySet(); } + private static class ModulesBasedFileFilter implements Mappings.DependentFilesFilter{ + private final CompileContext myContext; + private final Set myChunkModules; + private final Map> myCache = new HashMap>(); + + private ModulesBasedFileFilter(CompileContext context, ModuleChunk chunk) { + myContext = context; + myChunkModules = chunk.getModules(); + } + + @Override + public boolean accept(File file) { + final RootDescriptor moduleAndRoot = myContext.getModuleAndRoot(file); + if (moduleAndRoot == null) { + return true; + } + final Module moduleOfFile = moduleAndRoot.module; + if (myChunkModules.contains(moduleOfFile)) { + return true; + } + Set moduleOfFileWithDependencies = myCache.get(moduleOfFile); + if (moduleOfFileWithDependencies == null) { + moduleOfFileWithDependencies = ProjectPaths.getModulesWithDependentsRecursively(moduleOfFile, true); + myCache.put(moduleOfFile, moduleOfFileWithDependencies); + } + return intersects(moduleOfFileWithDependencies, myChunkModules); + } + + private static boolean intersects(Set set1, Set set2) { + if (set1.size() < set2.size()) { + return new HashSet(set1).removeAll(set2); + } + return new HashSet(set2).removeAll(set1); + } + } + } diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/ClasspathBootstrap.java b/jps/jps-builders/src/org/jetbrains/jps/server/ClasspathBootstrap.java index 65ba0c22b12d..ffc4b7efff97 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/ClasspathBootstrap.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/ClasspathBootstrap.java @@ -23,13 +23,13 @@ import com.intellij.uiDesigner.compiler.AlienFormFileException; import com.intellij.uiDesigner.core.GridConstraints; import com.jgoodies.forms.layout.CellConstraints; import com.sun.jna.Pointer; -import com.sun.jna.platform.FileMonitor; import gnu.trove.TIntHash; import net.n3.nanoxml.IXMLBuilder; import org.codehaus.groovy.GroovyException; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.MacroExpander; import org.jetbrains.jps.javac.JavacServer; +import com.intellij.openapi.util.io.FileUtilRt; import org.objectweb.asm.ClassWriter; import javax.tools.*; @@ -91,10 +91,10 @@ public class ClasspathBootstrap { cp.add(getResourcePath(com.google.protobuf.Message.class)); // protobuf cp.add(getResourcePath(org.jboss.netty.bootstrap.Bootstrap.class)); // netty cp.add(getResourcePath(TIntHash.class)); // trove + cp.add(getResourcePath(FileUtilRt.class)); // util-rt module cp.add(getResourcePath(FileUtil.class)); // util module cp.add(getResourcePath(Pointer.class)); // jna.jar cp.add(getResourcePath(CacheBuilder.class)); // guava - cp.add(getResourcePath(FileMonitor.class)); // jna-utils.jar cp.add(getResourcePath(ClassWriter.class)); // asm cp.add(getResourcePath(org.objectweb.asm.commons.EmptyVisitor.class)); // asm-commons cp.add(getResourcePath(MacroExpander.class)); // jps-model @@ -136,10 +136,10 @@ public class ClasspathBootstrap { cp.add(getResourcePath(com.google.protobuf.Message.class)); // protobuf cp.add(getResourcePath(org.jboss.netty.bootstrap.Bootstrap.class)); // netty cp.add(getResourcePath(TIntHash.class)); // trove + cp.add(getResourcePath(FileUtilRt.class)); // util-rt module cp.add(getResourcePath(FileUtil.class)); // util module cp.add(getResourcePath(Pointer.class)); // jna.jar cp.add(getResourcePath(CacheBuilder.class)); // guava - cp.add(getResourcePath(FileMonitor.class)); // jna-utils.jar cp.add(getResourcePath(org.jdom.input.SAXBuilder.class)); // jdom final Class optimizedFileManagerClass = getOptimizedFileManagerClass(); diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java index d6190d61d815..7ff64fdb13bc 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java @@ -806,7 +806,10 @@ public class Mappings { } } - private boolean incrementalDecision(final DependencyContext.S owner, final Proto member, final Collection affectedFiles) { + private boolean incrementalDecision(final DependencyContext.S owner, + final Proto member, + final Collection affectedFiles, + DependentFilesFilter filter) { final boolean isField = member instanceof FieldRepr; final Util self = new Util(this); @@ -842,19 +845,33 @@ public class Mappings { if (ClassRepr.getPackageName(myContext.getValue(className)).equals(packageName)) { final String f = myContext.getValue(fileName); - debug("Adding: ", f); - affectedFiles.add(new File(f)); + final File file = new File(f); + if (filter.accept(file)) { + debug("Adding: ", f); + affectedFiles.add(file); + } } } return true; } + public interface DependentFilesFilter { + DependentFilesFilter ALL_FILES = new DependentFilesFilter() { + @Override + public boolean accept(File file) { + return true; + } + }; + + boolean accept(File file); + } + public boolean differentiate(final Mappings delta, final Collection removed, final Collection filesToCompile, final Collection compiledFiles, - final Collection affectedFiles) { + final Collection affectedFiles, DependentFilesFilter filter) { synchronized (myLock) { debug("Begin of Differentiate:"); @@ -926,7 +943,7 @@ public class Mappings { if (it.isAnnotation() && it.policy == RetentionPolicy.SOURCE) { debug("Annotation, retention policy = SOURCE => a switch to non-incremental mode requested"); - if (!incrementalDecision(it.outerClassName, it, affectedFiles)) { + if (!incrementalDecision(it.outerClassName, it, affectedFiles, filter)) { debug("End of Differentiate, returning false"); return false; } @@ -970,7 +987,7 @@ public class Mappings { if (removedtargets.contains(ElementType.LOCAL_VARIABLE)) { debug("Removed target contains LOCAL_VARIABLE => a switch to non-incremental mode requested"); - if (!incrementalDecision(it.outerClassName, it, affectedFiles)) { + if (!incrementalDecision(it.outerClassName, it, affectedFiles, filter)) { debug("End of Differentiate, returning false"); return false; } @@ -1396,7 +1413,7 @@ public class Mappings { if ((f.access & Opcodes.ACC_PRIVATE) == 0 && (f.access & mask) == mask && f.hasValue()) { debug("Field had value and was (non-private) final static => a switch to non-incremental mode requested"); - if (!incrementalDecision(it.name, f, affectedFiles)) { + if (!incrementalDecision(it.name, f, affectedFiles, filter)) { debug("End of Differentiate, returning false"); return false; } @@ -1417,7 +1434,7 @@ public class Mappings { if ((field.access & Opcodes.ACC_PRIVATE) == 0 && (field.access & mask) == mask) { if ((d.base() & Difference.ACCESS) > 0 || (d.base() & Difference.VALUE) > 0) { debug("Inline field changed it's access or value => a switch to non-incremental mode requested"); - if (!incrementalDecision(it.name, field, affectedFiles)) { + if (!incrementalDecision(it.name, field, affectedFiles, filter)) { debug("End of Differentiate, returning false"); return false; } @@ -1633,40 +1650,46 @@ public class Mappings { if (delta.isDifferentiated()) { for (DependencyContext.S c : delta.getChangedClasses()) { - myClassToSubclasses.remove(c); - final Collection subClasses = delta.myClassToSubclasses.get(c); - if (subClasses != null) { - myClassToSubclasses.put(c, subClasses); + myClassToSubclasses.replace(c, subClasses); + } + else { + myClassToSubclasses.remove(c); } - myClassToSourceFile.remove(c); - final DependencyContext.S sourceFile = delta.myClassToSourceFile.get(c); - if (sourceFile != null) { myClassToSourceFile.put(c, sourceFile); } + else { + myClassToSourceFile.remove(c); + } } for (DependencyContext.S f : delta.getChangedFiles()) { - mySourceFileToClasses.remove(f); final Collection classes = delta.mySourceFileToClasses.get(f); if (classes != null) { - mySourceFileToClasses.put(f, classes); + mySourceFileToClasses.replace(f, classes); + } + else { + mySourceFileToClasses.remove(f); } - mySourceFileToUsages.remove(f); final Collection clusters = delta.mySourceFileToUsages.get(f); if (clusters != null) { - mySourceFileToUsages.put(f, clusters); + mySourceFileToUsages.replace(f, clusters); + } + else { + mySourceFileToUsages.remove(f); } - mySourceFileToAnnotationUsages.remove(f); final Collection usages = delta.mySourceFileToAnnotationUsages.get(f); if (usages != null) { - mySourceFileToAnnotationUsages.put(f, usages); + mySourceFileToAnnotationUsages.replace(f, usages); + } + else { + mySourceFileToAnnotationUsages.remove(f); } } } @@ -1711,8 +1734,7 @@ public class Mappings { changed |= past.addAll(now); if (changed) { - myClassToClassDependency.remove(aClass); - myClassToClassDependency.put(aClass, past); + myClassToClassDependency.replace(aClass, past); } } } diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/MultiMaplet.java b/jps/model/src/org/jetbrains/ether/dependencyView/MultiMaplet.java index a7152b3684dc..15a2875086e3 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/MultiMaplet.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/MultiMaplet.java @@ -30,6 +30,7 @@ interface MultiMaplet { Collection get(final K key); void put(final K key, final V value); void put(final K key, final Collection value); + void replace(final K key, final Collection value); void putAll(MultiMaplet m); void replaceAll(MultiMaplet m); void remove(final K key); diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/PersistentMultiMaplet.java b/jps/model/src/org/jetbrains/ether/dependencyView/PersistentMultiMaplet.java index f1d288696244..e5497ab73994 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/PersistentMultiMaplet.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/PersistentMultiMaplet.java @@ -66,6 +66,21 @@ class PersistentMultiMaplet implements MultiMaplet { } } + @Override + public void replace(K key, Collection value) { + try { + if (value == null) { + myMap.remove(key); + } + else { + myMap.put(key, value); + } + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + @Override public void put(final K key, final Collection value) { try { @@ -149,9 +164,7 @@ class PersistentMultiMaplet implements MultiMaplet { @Override public void replaceAll(MultiMaplet m) { for (Map.Entry> entry : m.entrySet()) { - final K key = entry.getKey(); - remove(key); - put(key, entry.getValue()); + replace(entry.getKey(), entry.getValue()); } } diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/TransientMultiMaplet.java b/jps/model/src/org/jetbrains/ether/dependencyView/TransientMultiMaplet.java index 7a5f2b85eb90..71aafd8696c8 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/TransientMultiMaplet.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/TransientMultiMaplet.java @@ -72,6 +72,16 @@ class TransientMultiMaplet implements MultiMaplet { } } + @Override + public void replace(K key, Collection value) { + if (value == null) { + myMap.remove(key); + } + else { + myMap.put(key, value); + } + } + @Override public void put(final K key, final V value) { final Collection x = constr.create(); @@ -111,8 +121,7 @@ class TransientMultiMaplet implements MultiMaplet { @Override public void replaceAll(MultiMaplet m) { for (Map.Entry> e : m.entrySet()) { - remove(e.getKey()); - put(e.getKey(), e.getValue()); + replace(e.getKey(), e.getValue()); } } diff --git a/jps/src/org/jetbrains/ether/ProjectWrapper.java b/jps/src/org/jetbrains/ether/ProjectWrapper.java index 01811ee5a439..05c22f89ada4 100644 --- a/jps/src/org/jetbrains/ether/ProjectWrapper.java +++ b/jps/src/org/jetbrains/ether/ProjectWrapper.java @@ -1163,7 +1163,8 @@ public class ProjectWrapper { final Collection affected = new HashSet(); - final boolean incremental = dependencyMapping.differentiate(delta, removed, files, compiled, affected); + final boolean incremental = dependencyMapping.differentiate(delta, removed, files, compiled, affected, + Mappings.DependentFilesFilter.ALL_FILES); for (File a : affected) { affectedFiles.add(FileUtil.toSystemIndependentName(a.getAbsolutePath())); diff --git a/platform/core-api/src/com/intellij/psi/PsiElement.java b/platform/core-api/src/com/intellij/psi/PsiElement.java index f26dbf06b44d..99bc7789c90c 100644 --- a/platform/core-api/src/com/intellij/psi/PsiElement.java +++ b/platform/core-api/src/com/intellij/psi/PsiElement.java @@ -269,7 +269,7 @@ public interface PsiElement extends UserDataHolder, Iconable { * @return the element which was actually added (either element or its copy). * @throws IncorrectOperationException if the modification is not supported or not possible for some reason. */ - PsiElement addBefore(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException; + PsiElement addBefore(@NotNull PsiElement element, @Nullable PsiElement anchor) throws IncorrectOperationException; /** * Adds a child to this PSI element, after the specified anchor element. @@ -279,7 +279,7 @@ public interface PsiElement extends UserDataHolder, Iconable { * @return the element which was actually added (either element or its copy). * @throws IncorrectOperationException if the modification is not supported or not possible for some reason. */ - PsiElement addAfter(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException; + PsiElement addAfter(@NotNull PsiElement element, @Nullable PsiElement anchor) throws IncorrectOperationException; /** * Checks if it is possible to add the specified element as a child to this element, diff --git a/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java b/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java index c092c70e2d10..9c751afbed35 100644 --- a/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java +++ b/platform/core-api/src/com/intellij/psi/search/LocalSearchScope.java @@ -41,11 +41,11 @@ public class LocalSearchScope extends SearchScope { public static final LocalSearchScope EMPTY = new LocalSearchScope(PsiElement.EMPTY_ARRAY); private String myDisplayName; - public LocalSearchScope(PsiElement scope) { + public LocalSearchScope(@NotNull PsiElement scope) { this(scope, null); } - public LocalSearchScope(PsiElement scope, String displayName) { + public LocalSearchScope(@NotNull PsiElement scope, @Nullable String displayName) { this(new PsiElement[]{scope}); myDisplayName = displayName; } @@ -54,16 +54,17 @@ public class LocalSearchScope extends SearchScope { this(scope, null); } - public LocalSearchScope(PsiElement[] scope, String displayName) { + public LocalSearchScope(PsiElement[] scope, @Nullable String displayName) { this(scope, displayName, false); } - public LocalSearchScope(final PsiElement[] scope, final String displayName, final boolean ignoreInjectedPsi) { + public LocalSearchScope(final PsiElement[] scope, @Nullable final String displayName, final boolean ignoreInjectedPsi) { myIgnoreInjectedPsi = ignoreInjectedPsi; myDisplayName = displayName; Set localScope = new LinkedHashSet(scope.length); for (final PsiElement element : scope) { + LOG.assertTrue(element != null, "null element"); LOG.assertTrue(element.getContainingFile() != null, element.getClass().getName()); if (element instanceof PsiFile) { List files = ((PsiFile)element).getViewProvider().getAllFiles(); diff --git a/platform/core-impl/src/com/intellij/core/CoreASTFactory.java b/platform/core-impl/src/com/intellij/core/CoreASTFactory.java index 5e91b4fc3e57..a70a1eb13b1f 100644 --- a/platform/core-impl/src/com/intellij/core/CoreASTFactory.java +++ b/platform/core-impl/src/com/intellij/core/CoreASTFactory.java @@ -60,6 +60,7 @@ public class CoreASTFactory extends ASTFactory implements DefaultASTFactory { return new LeafPsiElement(type, text); } + @Override public LeafElement createComment(IElementType type, CharSequence text) { return new PsiCoreCommentImpl(type, text); } diff --git a/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java b/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java index 83dd5c3e9abd..1477e2344d70 100644 --- a/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java +++ b/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java @@ -111,7 +111,7 @@ public class StubBasedPsiElementBase extends ASTDelegateP "; stubTree=" + stubTree; PsiElement each = this; while (each != null) { - message += "\n each=" + each + " of class " + each.getClass(); + message += "\n each of class " + each.getClass(); if (each instanceof StubBasedPsiElementBase) { message += "; node=" + ((StubBasedPsiElementBase)each).myNode + "; stub=" + ((StubBasedPsiElementBase)each).myStub; each = ((StubBasedPsiElementBase)each).getParentByStub(); @@ -154,11 +154,11 @@ public class StubBasedPsiElementBase extends ASTDelegateP public boolean isValid() { T stub = myStub; if (stub != null) { - if (stub instanceof PsiFileStub) { - return stub.getPsi().isValid(); + PsiElement parentPsi = stub.getParentStub().getPsi(); + if (parentPsi instanceof PsiFileImpl) { + return ((PsiFileImpl) parentPsi).isStubBasedChildValid(this); } - - return stub.getParentStub().getPsi().isValid(); + return parentPsi.isValid(); } return super.isValid(); diff --git a/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java b/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java index 6ddebaf8b7f8..505689a11b30 100644 --- a/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java +++ b/platform/core-impl/src/com/intellij/lang/impl/PsiBuilderImpl.java @@ -423,6 +423,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder, AS return myType; } + @Override public void remapTokenType(IElementType type) { //assert myType != null && type != null; myType = type; @@ -547,6 +548,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder, AS return myParsed; } + @Override public ASTNodeBuilder getBuilder() { return myBuilder; } diff --git a/platform/core-impl/src/com/intellij/openapi/editor/ex/DocumentBulkUpdateListener.java b/platform/core-impl/src/com/intellij/openapi/editor/ex/DocumentBulkUpdateListener.java index b85db01dc00b..999482c517df 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/ex/DocumentBulkUpdateListener.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/ex/DocumentBulkUpdateListener.java @@ -24,7 +24,7 @@ import com.intellij.util.messages.Topic; import org.jetbrains.annotations.NotNull; public interface DocumentBulkUpdateListener { - Topic TOPIC = Topic.create("Bulk document change notifcation like reformat, etc.", DocumentBulkUpdateListener.class); + Topic TOPIC = Topic.create("Bulk document change notification like reformat, etc.", DocumentBulkUpdateListener.class); void updateStarted(@NotNull Document doc); void updateFinished(@NotNull Document doc); diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/CharArray.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/CharArray.java index a3f9d7d5b652..08c65c2ac35f 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/CharArray.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/CharArray.java @@ -44,7 +44,7 @@ abstract class CharArray implements CharSequenceBackedByArray { private static final boolean DISABLE_DEFERRED_PROCESSING = Boolean.getBoolean("idea.document.deny.deferred.changes"); @SuppressWarnings("UseOfArchaicSystemPropertyAccessors") - private static final boolean DEBUG_DEFERRED_PROCESSING = LOG.isDebugEnabled() || Boolean.getBoolean("idea.document.debug.bulk.processing"); + private static final boolean DEBUG_DEFERRED_PROCESSING = LOG.isDebugEnabled() || Boolean.getBoolean("idea.document.debug.bulk.processing") || DocumentImpl.CHECK_DOCUMENT_CONSISTENCY; /** * We can't exclude possibility of situation when 'defer changes' state is {@link #setDeferredChangeMode(boolean) entered} * but not exited, hence, we want to perform automatic flushing if necessary in order to avoid memory leaks. This constant holds diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java index 18c0a2347654..e2a823c10e71 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java @@ -50,6 +50,7 @@ import java.util.concurrent.CopyOnWriteArrayList; public class DocumentImpl extends UserDataHolderBase implements DocumentEx { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.DocumentImpl"); + public static boolean CHECK_DOCUMENT_CONSISTENCY = ApplicationManager.getApplication().isUnitTestMode(); private final CopyOnWriteArrayList myDocumentListeners = ContainerUtil.createEmptyCOWList(); private final RangeMarkerTree myRangeMarkers = new RangeMarkerTree(this); diff --git a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java index 9bb2fe2f2d72..af2a1cab97f5 100644 --- a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java +++ b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java @@ -144,7 +144,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi } @Nullable - protected PsiFile getPsiInner(final Language target) { + protected PsiFile getPsiInner(@NotNull Language target) { if (target != getBaseLanguage()) { return null; } @@ -510,6 +510,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi } if (myContent != null) return myContent; return myContent = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override @NotNull public CharSequence compute() { return myFile.calcTreeElement().getText(); diff --git a/platform/core-impl/src/com/intellij/psi/impl/AbstractModificationTracker.java b/platform/core-impl/src/com/intellij/psi/impl/AbstractModificationTracker.java index d95321ece57a..e8e5cc3e3899 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/AbstractModificationTracker.java +++ b/platform/core-impl/src/com/intellij/psi/impl/AbstractModificationTracker.java @@ -17,6 +17,7 @@ package com.intellij.psi.impl; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; /** * @author Roman.Chernyatchik @@ -40,7 +41,8 @@ public abstract class AbstractModificationTracker implements PsiTreeChangePrepro myPsiManager.addTreeChangePreprocessor(this); } - public void treeChanged(final PsiTreeChangeEventImpl event) { + @Override + public void treeChanged(@NotNull final PsiTreeChangeEventImpl event) { boolean changedInsideCodeBlock = false; switch (event.getCode()) { diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiModificationTrackerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/PsiModificationTrackerImpl.java index 360720da51a6..d3c6b410abd8 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiModificationTrackerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiModificationTrackerImpl.java @@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.messages.MessageBus; +import org.jetbrains.annotations.NotNull; import java.util.concurrent.atomic.AtomicLong; @@ -68,7 +69,7 @@ public class PsiModificationTrackerImpl implements PsiModificationTracker, PsiTr } @Override - public void treeChanged(PsiTreeChangeEventImpl event) { + public void treeChanged(@NotNull PsiTreeChangeEventImpl event) { myModificationCount.getAndIncrement(); if (event.getParent() instanceof PsiDirectory) { incOutOfCodeBlockModificationCounter(); diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessor.java b/platform/core-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessor.java index 35224e14613f..7eaac7f30076 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessor.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessor.java @@ -17,6 +17,7 @@ package com.intellij.psi.impl; import com.intellij.openapi.extensions.ExtensionPointName; +import org.jetbrains.annotations.NotNull; /** * @author yole @@ -24,5 +25,5 @@ import com.intellij.openapi.extensions.ExtensionPointName; public interface PsiTreeChangePreprocessor { ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.psi.treeChangePreprocessor"); - void treeChanged(PsiTreeChangeEventImpl event); + void treeChanged(@NotNull PsiTreeChangeEventImpl event); } diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index dd202dd57883..d3ff3e9ae771 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -249,6 +249,20 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF return findTreeForStub(ast, stubs, stub); } + public boolean isStubBasedChildValid(@NotNull StubBasedPsiElementBase psi) { + StubElement fileStub = getStub(); + if (fileStub != null) { + synchronized (myStubLock) { + fileStub = getStub(); + StubElement childStub = psi.getStub(); + if (fileStub != null && childStub != null && fileStub != childStub.getParentStub()) { + return false; + } + } + } + return isValid(); + } + @Nullable private static ASTNode findTreeForStub(ASTNode tree, final Iterator> stubs, final StubElement stub) { final IElementType type = tree.getElementType(); diff --git a/platform/icons/src/actions/checked_16x16.png b/platform/icons/src/actions/checked_16x16.png new file mode 100644 index 000000000000..d55c1fc133c9 Binary files /dev/null and b/platform/icons/src/actions/checked_16x16.png differ diff --git a/platform/icons/src/actions/checked_16x16_selected.png b/platform/icons/src/actions/checked_16x16_selected.png new file mode 100644 index 000000000000..2dfa1eda3c12 Binary files /dev/null and b/platform/icons/src/actions/checked_16x16_selected.png differ diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java index cc6c34625ef8..689ad61035da 100644 --- a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java +++ b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java @@ -58,7 +58,7 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D private void addCustomFoldingRegionsRecursively(@Nullable FoldingStack foldingStack, @NotNull ASTNode node, - List descriptors, + @NotNull List descriptors, int currDepth) { FoldingStack localFoldingStack = isCustomFoldingRoot(node) || foldingStack == null ? new FoldingStack(node) : foldingStack; for (ASTNode child = node.getFirstChildNode(); child != null; child = child.getTreeNext()) { @@ -196,7 +196,7 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D } private static class FoldingStack extends Stack { - private ASTNode owner; + private final ASTNode owner; public FoldingStack(@NotNull ASTNode owner) { super(1); @@ -205,7 +205,7 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D @NotNull public ASTNode getOwner() { - return this.owner; + return owner; } } } diff --git a/platform/lang-impl/src/com/intellij/codeEditor/printing/TextPainter.java b/platform/lang-impl/src/com/intellij/codeEditor/printing/TextPainter.java index e36efc870d41..b57def2b36be 100644 --- a/platform/lang-impl/src/com/intellij/codeEditor/printing/TextPainter.java +++ b/platform/lang-impl/src/com/intellij/codeEditor/printing/TextPainter.java @@ -27,7 +27,6 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; @@ -93,8 +92,6 @@ public class TextPainter implements Printable { myFileName = fileName; mySegmentEnd = myDocument.getTextLength(); - PsiDocumentManager.getInstance(project).commitAllDocuments(); - myFileType = psiFile.getFileType(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java index 16e61e3fa520..df0cea32c0c2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java @@ -50,6 +50,8 @@ public class ExternalToolPass extends TextEditorHighlightingPass { private final Map myAnnotator2DataMap; + private final ExternalToolPassFactory myExternalToolPassFactory; + private static class MyData { final PsiFile myPsiRoot; final Object myCollectedInfo; @@ -61,7 +63,8 @@ public class ExternalToolPass extends TextEditorHighlightingPass { } } - public ExternalToolPass(@NotNull PsiFile file, + public ExternalToolPass(@NotNull ExternalToolPassFactory externalToolPassFactory, + @NotNull PsiFile file, @NotNull Editor editor, int startOffset, int endOffset) { @@ -72,6 +75,7 @@ public class ExternalToolPass extends TextEditorHighlightingPass { myAnnotationHolder = new AnnotationHolderImpl(new AnnotationSession(file)); myAnnotator2DataMap = new HashMap(); + myExternalToolPassFactory = externalToolPassFactory; } @Override @@ -159,7 +163,7 @@ public class ExternalToolPass extends TextEditorHighlightingPass { r.run(); } else { - ApplicationManager.getApplication().executeOnPooledThread(r); + myExternalToolPassFactory.scheduleExternalActivity(myFile, r); } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPassFactory.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPassFactory.java index 4dec3b2a23b6..f719f5e89cf4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPassFactory.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPassFactory.java @@ -28,6 +28,8 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiFile; +import com.intellij.util.ui.update.MergingUpdateQueue; +import com.intellij.util.ui.update.Update; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,10 +40,15 @@ import java.util.List; * @author cdr */ public class ExternalToolPassFactory extends AbstractProjectComponent implements TextEditorHighlightingPassFactory { + private final MergingUpdateQueue myExternalActivitiesQueue; + public ExternalToolPassFactory(Project project, TextEditorHighlightingPassRegistrar highlightingPassRegistrar) { super(project); // start after PostHighlightingPass completion since it could report errors that can prevent us to run highlightingPassRegistrar.registerTextEditorHighlightingPass(this, new int[]{Pass.POST_UPDATE_ALL}, null, true, Pass.EXTERNAL_TOOLS); + + myExternalActivitiesQueue = new MergingUpdateQueue("ExternalActivitiesQueue", 300, true, MergingUpdateQueue.ANY_COMPONENT, project, + null, false); } @Override @@ -54,11 +61,11 @@ public class ExternalToolPassFactory extends AbstractProjectComponent implements @Override @Nullable public TextEditorHighlightingPass createHighlightingPass(@NotNull PsiFile file, @NotNull final Editor editor) { - TextRange textRange = file.getTextRange(); + TextRange textRange = FileStatusMap.getDirtyTextRange(editor, Pass.EXTERNAL_TOOLS) == null ? null : file.getTextRange(); if (textRange == null || !externalAnnotatorsDefined(file)) { return null; } - return new ExternalToolPass(file, editor, textRange.getStartOffset(), textRange.getEndOffset()); + return new ExternalToolPass(this, file, editor, textRange.getStartOffset(), textRange.getEndOffset()); } private static boolean externalAnnotatorsDefined(PsiFile file) { @@ -70,4 +77,13 @@ public class ExternalToolPassFactory extends AbstractProjectComponent implements } return false; } + + void scheduleExternalActivity(@NotNull PsiFile file, @NotNull final Runnable r) { + myExternalActivitiesQueue.queue(new Update(file) { + @Override + public void run() { + r.run(); + } + }); + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index ef1ca8393cf9..978dbe22d15d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -890,8 +890,9 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable public boolean performGuardedChange(Runnable change, @Nullable final String debug) { checkValid(); - assert myLookupStartMarker.isValid(); - assert !myChangeGuard; + assert myLookupStartMarker != null : "null start before"; + assert myLookupStartMarker.isValid() : "invalid start"; + assert !myChangeGuard : "already in change"; myChangeGuard = true; final Document document = myEditor.getDocument(); @@ -911,7 +912,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable document.removeDocumentListener(spy); myChangeGuard = false; } - if (!myLookupStartMarker.isValid() || myDisposed) { + if (myDisposed || !myLookupStartMarker.isValid()) { hide(); return false; } @@ -924,7 +925,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable @Override public boolean vetoesHiding() { - return myChangeGuard || myDisposed; + return myChangeGuard; } public boolean isAvailableToUser() { diff --git a/platform/lang-impl/src/com/intellij/execution/rmi/RemoteProcessSupport.java b/platform/lang-impl/src/com/intellij/execution/rmi/RemoteProcessSupport.java index 0c163ed00a14..f6c95bf4276b 100644 --- a/platform/lang-impl/src/com/intellij/execution/rmi/RemoteProcessSupport.java +++ b/platform/lang-impl/src/com/intellij/execution/rmi/RemoteProcessSupport.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.execution.rmi; import com.intellij.execution.ExecutionException; diff --git a/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/GridCellImpl.java b/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/GridCellImpl.java index fc6488f989db..ae9624772796 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/GridCellImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/GridCellImpl.java @@ -363,7 +363,9 @@ public class GridCellImpl implements GridCell { service.setSize(getDimensionKey(), size, myContext.getProject()); if (myContext.getWindow() != 0) { final Window frame = SwingUtilities.getWindowAncestor(myPlaceholder); - service.setLocation(getDimensionKey(), frame.getLocationOnScreen()); + if (frame != null) { + service.setLocation(getDimensionKey(), frame.getLocationOnScreen()); + } } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java index af422a858909..1a7796276ff2 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java @@ -804,12 +804,7 @@ public class FindDialog extends DialogWrapper { gbConstraints.gridx++; gbConstraints.weightx = 1; gbConstraints.gridwidth = 2; - myScopeCombo = new ScopeChooserCombo(myProject, true, true, FindSettings.getInstance().getDefaultScopeName()) { - @Override - public Dimension getMinimumSize() { - return new Dimension(200, super.getMinimumSize().height); - } - }; + myScopeCombo = new ScopeChooserCombo(myProject, true, true, FindSettings.getInstance().getDefaultScopeName()); Disposer.register(myDisposable, myScopeCombo); scopePanel.add(myScopeCombo, gbConstraints); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java index dd3afc04bb4e..f7586f8ce300 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java @@ -175,7 +175,8 @@ public abstract class GotoActionBase extends AnAction { @Override public void onClose() { ourLastStrings.put(myInAction, Pair.create(popup.getEnteredText(), popup.getSelectedIndex())); - if (startedAction.equals(myInAction)) { + //noinspection ConstantConditions + if (startedAction != null && startedAction.equals(myInAction)) { myInAction = null; } if (filter != null) { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 08d9c320118f..9b63a06d17bc 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -253,8 +253,6 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo myViewContentPanel = new JPanel(); myPanel = new SimpleToolWindowPanel(true).setProvideQuickActions(false); myPanel.setContent(myViewContentPanel); - - myPanel.setBorder(new ToolWindow.Border(true, false, false, false)); } public String getName() { diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java index db21ded54762..b02c3272bc89 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java @@ -16,10 +16,13 @@ package com.intellij.ide.util.gotoByName; import com.intellij.concurrency.JobUtil; +import com.intellij.diagnostic.PluginException; +import com.intellij.ide.plugins.PluginManager; import com.intellij.ide.util.NavigationItemListCellRenderer; import com.intellij.navigation.ChooseByNameContributor; import com.intellij.navigation.NavigationItem; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbService; @@ -109,7 +112,13 @@ public abstract class ContributorsBasedGotoByModel implements ChooseByNameModel try { for (NavigationItem item : contributor.getItemsByName(name, pattern, myProject, checkBoxState)) { if (item == null) { - LOG.error("null item from contributor " + contributor + " for name " + name); + final PluginId pluginId = PluginManager.getPluginByClassName(contributor.getClass().getName()); + if (pluginId != null) { + LOG.error(new PluginException("null item from contributor " + contributor + " for name " + name, pluginId)); + } + else { + LOG.error("null item from contributor " + contributor + " for name " + name); + } continue; } diff --git a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java index 7dcd14a4b40b..48b78e2bee88 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java +++ b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java @@ -190,6 +190,15 @@ public class ScopeChooserCombo extends ComboboxWithBrowseButton implements Dispo return new Dimension(Math.min(400, preferredSize.width), preferredSize.height); } + @Override + public Dimension getMinimumSize() { + if (isMinimumSizeSet()) { + return super.getMinimumSize(); + } + Dimension minimumSize = super.getMinimumSize(); + return new Dimension(Math.min(200, minimumSize.width), minimumSize.height); + } + private void createPredefinedScopeDescriptors(DefaultComboBoxModel model) { for (SearchScope scope : getPredefinedScopes(myProject, DataManager.getInstance().getDataContext(), mySuggestSearchInLibs, myPrevSearchFiles, true, true)) { model.addElement(new ScopeDescriptor(scope)); diff --git a/platform/lang-impl/src/com/intellij/platform/ModuleAttachProcessor.java b/platform/lang-impl/src/com/intellij/platform/ModuleAttachProcessor.java index 90bd69e50224..e1768278e035 100644 --- a/platform/lang-impl/src/com/intellij/platform/ModuleAttachProcessor.java +++ b/platform/lang-impl/src/com/intellij/platform/ModuleAttachProcessor.java @@ -70,12 +70,15 @@ public class ModuleAttachProcessor extends ProjectAttachProcessor { token.finish(); } } - for(String file: projectDir.list()) { - if (FileUtil.getExtension(file).equals("iml")) { - VirtualFile imlFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(projectDir, file)); - if (imlFile != null) { - attachModule(project, imlFile, callback); - return true; + final String[] files = projectDir.list(); + if (files != null) { + for(String file: files) { + if (FileUtil.getExtension(file).equals("iml")) { + VirtualFile imlFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(projectDir, file)); + if (imlFile != null) { + attachModule(project, imlFile, callback); + return true; + } } } } diff --git a/platform/lang-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java b/platform/lang-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java index ec5ee72b429b..bc650fdf8ef4 100644 --- a/platform/lang-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java @@ -28,7 +28,6 @@ import com.intellij.psi.impl.SharedPsiElementImplUtil; import com.intellij.psi.impl.source.PsiFileImpl; import com.intellij.psi.impl.source.tree.FileElement; import com.intellij.psi.templateLanguages.OuterLanguageElement; -import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.ReflectionCache; import com.intellij.util.containers.ConcurrentHashMap; @@ -72,7 +71,7 @@ public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends Single } @Override - protected PsiFile getPsiInner(final Language target) { + protected PsiFile getPsiInner(@NotNull final Language target) { PsiFile file = myRoots.get(target); if (file == null) { if (isPhysical()) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java index 84e455f565d3..2d97fc4052a7 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java @@ -31,6 +31,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.event.DocumentListener; +import com.intellij.openapi.editor.ex.DocumentBulkUpdateListener; import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter; @@ -79,7 +80,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec private final List myListeners = ContainerUtil.createEmptyCOWList(); private final SmartPointerManagerImpl mySmartPointerManager; - public PsiDocumentManagerImpl(@NotNull Project project, + public PsiDocumentManagerImpl(@NotNull final Project project, @NotNull PsiManager psiManager, @NotNull SmartPointerManager smartPointerManager, @NotNull EditorFactory editorFactory, @@ -105,6 +106,12 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec fireDocumentCreated(document, psiFile); } }); + bus.connect().subscribe(DocumentBulkUpdateListener.TOPIC, new DocumentBulkUpdateListener.Adapter() { + @Override + public void updateFinished(@NotNull Document doc) { + documentCommitThread.queueCommit(project, doc, "Bulk update finished"); + } + }); ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() { @Override public void beforeWriteActionStart(Object action) { @@ -668,12 +675,13 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec commitNecessary = true; } + boolean fromRefresh = ApplicationManager.getApplication().hasWriteAction(ExternalChangeAction.class); if (commitNecessary) { myUncommittedDocuments.add(document); - myDocumentCommitThread.log("PDI: added to uncommitted", null, false, document, event, myUncommittedDocuments); - - myDocumentCommitThread.queueCommit(myProject, document, event); + if (!fromRefresh && !((DocumentEx)document).isInBulkUpdate()) { + myDocumentCommitThread.queueCommit(myProject, document, event); + } } // Consider that it's worth to perform complete re-parse instead of merge if the whole document text is replaced and @@ -683,7 +691,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec document.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE); } - if (commitNecessary && ApplicationManager.getApplication().hasWriteAction(ExternalChangeAction.class)){ + if (commitNecessary && fromRefresh){ commitDocument(document); } // avoid documents piling up during batch processing diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessorBase.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessorBase.java index 3e018129246b..fad5f62205e9 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessorBase.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessorBase.java @@ -18,6 +18,7 @@ package com.intellij.psi.impl; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; /** * @author yole @@ -31,7 +32,7 @@ public abstract class PsiTreeChangePreprocessorBase implements PsiTreeChangePrep } @Override - public void treeChanged(PsiTreeChangeEventImpl event) { + public void treeChanged(@NotNull PsiTreeChangeEventImpl event) { boolean changedInsideCodeBlock = false; switch (event.getCode()) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java index dde40cb8887b..ad73760f78ed 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java @@ -106,6 +106,7 @@ class SmartPsiElementPointerImpl implements SmartPointerEx myElement = element == null ? null : new SoftReference(element); } + @Override public E getCachedElement() { Reference ref = myElement; return ref == null ? null : ref.get(); diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/ShowSelectionHistoryAction.java b/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/ShowSelectionHistoryAction.java index 90bafa107ef6..843795e24455 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/ShowSelectionHistoryAction.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/ShowSelectionHistoryAction.java @@ -20,12 +20,14 @@ import com.intellij.history.core.LocalHistoryFacade; import com.intellij.history.integration.IdeaGateway; import com.intellij.history.integration.ui.views.SelectionHistoryDialog; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.actions.VcsContext; import com.intellij.openapi.vcs.actions.VcsContextWrapper; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsSelection; import com.intellij.vcsUtil.VcsSelectionUtil; +import org.jetbrains.annotations.Nullable; public class ShowSelectionHistoryAction extends ShowHistoryAction { @Override @@ -44,12 +46,23 @@ public class ShowSelectionHistoryAction extends ShowHistoryAction { return sel == null ? super.getText(e) : sel.getActionName(); } + @Override + public void update(AnActionEvent e) { + if (e.getData(PlatformDataKeys.EDITOR) == null) { + e.getPresentation().setVisible(false); + } + else { + super.update(e); + } + } + @Override protected boolean isEnabled(LocalHistoryFacade vcs, IdeaGateway gw, VirtualFile f, AnActionEvent e) { return super.isEnabled(vcs, gw, f, e) && !f.isDirectory() && getSelection(e) != null; } - private VcsSelection getSelection(AnActionEvent e) { + @Nullable + private static VcsSelection getSelection(AnActionEvent e) { VcsContext c = VcsContextWrapper.createCachedInstanceOn(e); return VcsSelectionUtil.getSelection(c); } diff --git a/platform/platform-api/src/com/intellij/openapi/progress/ProgressManagerQueue.java b/platform/platform-api/src/com/intellij/openapi/progress/ProgressManagerQueue.java index 18beef5fcedc..6e86c7bd2d74 100644 --- a/platform/platform-api/src/com/intellij/openapi/progress/ProgressManagerQueue.java +++ b/platform/platform-api/src/com/intellij/openapi/progress/ProgressManagerQueue.java @@ -37,11 +37,13 @@ public class ProgressManagerQueue extends AbstractTaskQueue { protected void runMe() { final Application app = ApplicationManager.getApplication(); if (app.isDispatchThread()) { + if (myTask.myProject != null && myTask.myProject.isDisposed()) return; myProgressManager.run(myTask); } else { ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { + if (myTask.myProject != null && myTask.myProject.isDisposed()) return; myProgressManager.run(myTask); } }); diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java index 62c78bbb0f6c..c7d0dcbacf19 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java @@ -462,7 +462,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom boolean hasFocus) { if (value instanceof MyNode) { final MyNode node = ((MyNode)value); - setIcon(node.getConfigurable().getIcon(expanded)); + setIcon(node.getIcon(expanded)); final Font font = UIUtil.getTreeFont(); if (node.isDisplayInBold()) { setFont(font.deriveFont(Font.BOLD)); @@ -699,8 +699,8 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom throw new ConfigurationException("Name should contain non-space characters"); } if (names.contains(name)) { - final NamedConfigurable selectedConfugurable = getSelectedConfugurable(); - if (selectedConfugurable == null || !Comparing.strEqual(selectedConfugurable.getDisplayName(), name)) { + final NamedConfigurable selectedConfigurable = getSelectedConfugurable(); + if (selectedConfigurable == null || !Comparing.strEqual(selectedConfigurable.getDisplayName(), name)) { selectNodeInTree(node); } throw new ConfigurationException(CommonBundle.message("smth.already.exist.error.message", prefix, name), title); @@ -836,6 +836,16 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom public void setDisplayInBold(boolean displayInBold) { myDisplayInBold = displayInBold; } + + @Nullable + public Icon getIcon(boolean expanded) { + // thanks to invokeLater() in TreeUtil.showAndSelect(), we can get calls to getIcon() after the tree has been disposed + final NamedConfigurable configurable = getConfigurable(); + if (configurable != null) { + return configurable.getIcon(expanded); + } + return null; + } } @SuppressWarnings({"ConstantConditions"}) diff --git a/platform/platform-api/src/com/intellij/ui/ColoredTreeCellRenderer.java b/platform/platform-api/src/com/intellij/ui/ColoredTreeCellRenderer.java index 9a7a047a812b..98757ca2ff8f 100644 --- a/platform/platform-api/src/com/intellij/ui/ColoredTreeCellRenderer.java +++ b/platform/platform-api/src/com/intellij/ui/ColoredTreeCellRenderer.java @@ -56,7 +56,7 @@ public abstract class ColoredTreeCellRenderer extends SimpleColoredComponent imp clear(); mySelected = selected; - myFocused = tree.hasFocus(); + myFocused = isFocused(); // We paint background if and only if tree path is selected and tree has focus. // If path is selected and tree is not focused then we just paint focused border. @@ -104,7 +104,7 @@ public abstract class ColoredTreeCellRenderer extends SimpleColoredComponent imp super.setIconOpaque(false); } else { - super.setOpaque(myOpaque || selected && hasFocus || selected && tree.hasFocus()); // draw selection background even for non-opaque tree + super.setOpaque(myOpaque || selected && hasFocus || selected && isFocused()); // draw selection background even for non-opaque tree } if (tree.getUI() instanceof UIUtil.MacTreeUI) { @@ -121,6 +121,10 @@ public abstract class ColoredTreeCellRenderer extends SimpleColoredComponent imp return this; } + protected boolean isFocused() { + return myTree.hasFocus(); + } + public void setOpaque(boolean isOpaque) { myOpaque = isOpaque; super.setOpaque(isOpaque); diff --git a/platform/platform-api/src/com/intellij/ui/HtmlListCellRenderer.java b/platform/platform-api/src/com/intellij/ui/HtmlListCellRenderer.java index 179e6418c92d..f383b18eb0b6 100644 --- a/platform/platform-api/src/com/intellij/ui/HtmlListCellRenderer.java +++ b/platform/platform-api/src/com/intellij/ui/HtmlListCellRenderer.java @@ -90,6 +90,15 @@ public abstract class HtmlListCellRenderer extends ListCellRendererWrapper } } + public void append(SimpleColoredText text) { + int length = text.getTexts().size(); + for (int i = 0; i < length; i++) { + String fragment = text.getTexts().get(i); + SimpleTextAttributes attributes = text.getAttributes().get(i); + append(fragment, attributes); + } + } + private static void formatStyle(final StringBuilder builder, final SimpleTextAttributes attributes) { final Color fgColor = attributes.getFgColor(); final Color bgColor = attributes.getBgColor(); diff --git a/platform/platform-api/src/com/intellij/ui/RawCommandLineEditor.java b/platform/platform-api/src/com/intellij/ui/RawCommandLineEditor.java index f2af238df062..5b0296ecfd54 100644 --- a/platform/platform-api/src/com/intellij/ui/RawCommandLineEditor.java +++ b/platform/platform-api/src/com/intellij/ui/RawCommandLineEditor.java @@ -15,7 +15,9 @@ */ package com.intellij.ui; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.ui.LabeledComponent; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.IconLoader; @@ -27,6 +29,8 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class RawCommandLineEditor extends JPanel { + private static final Logger LOG = Logger.getInstance("#com.intellij.ui.RawCommandLineEditor"); + private final TextFieldWithBrowseButton myTextField; private String myDialogCaption = ""; @@ -34,6 +38,14 @@ public class RawCommandLineEditor extends JPanel { super(new BorderLayout()); myTextField = new TextFieldWithBrowseButton(new ActionListener() { public void actionPerformed(ActionEvent e) { + if (myDialogCaption == null) { + Container parent = getParent(); + if (parent instanceof LabeledComponent) { + parent = parent.getParent(); + } + LOG.error("Did not call RawCommandLineEditor.setDialogCaption() in " + parent); + myDialogCaption = "Parameters"; + } Messages.showTextAreaDialog(myTextField.getTextField(), myDialogCaption, "EditParametersPopupWindow"); } }); diff --git a/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java b/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java index d568198030c0..a267e62a87d8 100644 --- a/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java +++ b/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java @@ -81,4 +81,15 @@ public class SimpleColoredText { public ArrayList getAttributes() { return myAttributes; } + + public SimpleColoredText derive(SimpleTextAttributes attributes, boolean override) { + SimpleColoredText result = new SimpleColoredText(); + for (int i = 0; i < myTexts.size(); i++) { + SimpleTextAttributes overridden = override + ? SimpleTextAttributes.merge(myAttributes.get(i), attributes) + : SimpleTextAttributes.merge(attributes, myAttributes.get(i)); + result.append(myTexts.get(i), overridden); + } + return result; + } } diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java index 45c466bf66e9..53ec6dcc98ab 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java @@ -337,7 +337,9 @@ public class JBTabsImpl extends JComponent BufferedImage img; if (cmp.isShowing()) { - img = new BufferedImage(cmp.getWidth(), cmp.getHeight(), BufferedImage.TYPE_INT_ARGB); + final int width = cmp.getWidth(); + final int height = cmp.getHeight(); + img = new BufferedImage(width > 0 ? width : 500, height > 0 ? height : 500, BufferedImage.TYPE_INT_ARGB); Graphics2D g = img.createGraphics(); cmp.paint(g); } else { diff --git a/platform/platform-api/src/com/intellij/util/ui/StatusText.java b/platform/platform-api/src/com/intellij/util/ui/StatusText.java index 2510f91d6940..043b377610bc 100644 --- a/platform/platform-api/src/com/intellij/util/ui/StatusText.java +++ b/platform/platform-api/src/com/intellij/util/ui/StatusText.java @@ -16,7 +16,6 @@ package com.intellij.util.ui; -import com.intellij.ui.ScreenUtil; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.UIBundle; @@ -134,6 +133,7 @@ public abstract class StatusText { myText = ""; myComponent.clear(); myClickListeners.clear(); + if (myOwner != null) myOwner.repaint(); return this; } @@ -154,7 +154,7 @@ public abstract class StatusText { myText += text; myComponent.append(text, attrs); myClickListeners.add(listener); - + if (myOwner != null) myOwner.repaint(); return this; } diff --git a/platform/platform-impl/src/com/intellij/notification/EventLog.java b/platform/platform-impl/src/com/intellij/notification/EventLog.java index 2ac011e9a5b9..89e8189e62e0 100644 --- a/platform/platform-impl/src/com/intellij/notification/EventLog.java +++ b/platform/platform-impl/src/com/intellij/notification/EventLog.java @@ -36,6 +36,7 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.util.*; @@ -403,7 +404,7 @@ public class EventLog implements Notifications { myProjectModel.addNotification(notification); - ApplicationManager.getApplication().invokeLater(new Runnable() { + StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() { @Override public void run() { if (!ShutDownTracker.isShutdownHookRunning() && !myProject.isDisposed()) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/highlighter/EditorHighlighterFactoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/highlighter/EditorHighlighterFactoryImpl.java index e53742e1e2f4..4c32efd347a6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/highlighter/EditorHighlighterFactoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/highlighter/EditorHighlighterFactoryImpl.java @@ -16,6 +16,7 @@ package com.intellij.openapi.editor.highlighter; import com.intellij.lang.Language; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter; @@ -32,6 +33,8 @@ import org.jetbrains.annotations.Nullable; * @author yole */ public class EditorHighlighterFactoryImpl extends EditorHighlighterFactory { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.highlighter.EditorHighlighterFactoryImpl"); + @Override public EditorHighlighter createEditorHighlighter(SyntaxHighlighter highlighter, final EditorColorsScheme colors) { if (highlighter == null) highlighter = new PlainSyntaxHighlighter(); @@ -74,8 +77,16 @@ public class EditorHighlighterFactoryImpl extends EditorHighlighterFactory { final ContentBasedFileSubstitutor[] processors = Extensions.getExtensions(ContentBasedFileSubstitutor.EP_NAME); SyntaxHighlighter highlighter = null; for (ContentBasedFileSubstitutor processor : processors) { - if (processor.isApplicable(project, vFile) && processor instanceof ContentBasedClassFileProcessor) { - highlighter = ((ContentBasedClassFileProcessor) processor).createHighlighter(project, vFile); + boolean applicable; + try { + applicable = processor.isApplicable(project, vFile); + } + catch (Exception e) { + LOG.error(e); + continue; + } + if (applicable && processor instanceof ContentBasedClassFileProcessor) { + highlighter = ((ContentBasedClassFileProcessor)processor).createHighlighter(project, vFile); } } if (highlighter == null) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index fb2f5a32ae26..b44e8d539581 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -5803,7 +5803,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi if (last != null && !(last instanceof EditorComponentImpl)) return; final Editor editor = getEditor(source); - if (action == MOVE && !editor.isViewer()) { + if (action == MOVE && !editor.isViewer() && myDraggedRange != null) { if (!FileDocumentManager.getInstance().requestWriting(editor.getDocument(), editor.getProject())) { return; } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java index bf47f92b6559..57309076daf1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java @@ -99,6 +99,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl myBus = ApplicationManager.getApplication().getMessageBus(); InvocationHandler handler = new InvocationHandler() { + @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { multicast(method, args); return null; @@ -135,17 +136,21 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl } } + @Override @NotNull public String getComponentName() { return "FileDocumentManager"; } + @Override public void initComponent() { } + @Override public void disposeComponent() { } + @Override @Nullable public Document getDocument(@NotNull final VirtualFile file) { DocumentEx document = (DocumentEx)getCachedDocument(file); @@ -167,6 +172,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl if (!(file instanceof LightVirtualFile || file.getFileSystem() instanceof DummyFileSystem)) { document.addDocumentListener( new DocumentAdapter() { + @Override public void documentChanged(DocumentEvent e) { final Document document = e.getDocument(); myUnsavedDocuments.add(document); @@ -205,6 +211,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl return EditorFactory.getInstance().createDocument(text); } + @Override @Nullable public Document getCachedDocument(@NotNull VirtualFile file) { Reference reference = file.getUserData(DOCUMENT_KEY); @@ -222,6 +229,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl public static void registerDocument(@NotNull final Document document, @NotNull VirtualFile virtualFile) { synchronized (lock) { virtualFile.putUserData(DOCUMENT_KEY, new SoftReference(document) { + @Override public Document get() { return document; } @@ -230,6 +238,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl } } + @Override @Nullable public VirtualFile getFile(@NotNull Document document) { return document.getUserData(FILE_KEY); @@ -269,6 +278,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl }); } + @Override public void saveAllDocuments() { ApplicationManager.getApplication().assertIsDispatchThread(); @@ -293,11 +303,13 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl } } + @Override public void saveDocument(@NotNull final Document document) { ApplicationManager.getApplication().assertIsDispatchThread(); if (!myUnsavedDocuments.contains(document)) return; ApplicationManager.getApplication().runWriteAction(new DocumentRunnable(document, null) { + @Override public void run() { _saveDocument(document); } @@ -394,6 +406,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl return lineSeparator; } + @Override @NotNull public String getLineSeparator(@Nullable VirtualFile file, @Nullable Project project) { String lineSeparator = file != null ? LoadTextUtil.getDetectedLineSeparator(file) : null; @@ -421,6 +434,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl return false; } + @Override public void reloadFiles(final VirtualFile... files) { for (VirtualFile file : files) { if (file.exists()) { @@ -432,6 +446,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl } } + @Override @NotNull public Document[] getUnsavedDocuments() { if (myUnsavedDocuments.isEmpty()) { @@ -442,15 +457,18 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl return list.toArray(new Document[list.size()]); } + @Override public boolean isDocumentUnsaved(@NotNull Document document) { return myUnsavedDocuments.contains(document); } + @Override public boolean isFileModified(@NotNull VirtualFile file) { final Document doc = getCachedDocument(file); return doc != null && isDocumentUnsaved(doc) && doc.getModificationStamp() != file.getModificationStamp(); } + @Override public void propertyChanged(final VirtualFilePropertyEvent event) { if (VirtualFile.PROP_WRITABLE.equals(event.getPropertyName())) { final VirtualFile file = event.getFile(); @@ -459,6 +477,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl ApplicationManager.getApplication().runWriteAction( new ExternalChangeAction() { + @Override public void run() { document.setReadOnly(!event.getFile().isWritable()); } @@ -478,6 +497,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl return ft.isBinary() && BinaryFileTypeDecompilers.INSTANCE.forFileType(ft) == null; } + @Override public void contentsChanged(VirtualFileEvent event) { if (event.isFromSave()) return; final VirtualFile file = event.getFile(); @@ -499,6 +519,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl LOG.info(" oldFileStamp:" + oldFileStamp); Runnable askReloadRunnable = new Runnable() { + @Override public void run() { if (!file.isValid()) return; if (askReloadFromDisk(file, document)) { @@ -518,6 +539,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl myMultiCaster.fileWithNoDocumentChanged(file); } + @Override public void reloadFromDisk(@NotNull final Document document) { ApplicationManager.getApplication().assertIsDispatchThread(); final VirtualFile file = getFile(document); @@ -527,9 +549,11 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl final Project project = ProjectLocator.getInstance().guessProjectForFile(file); CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override public void run() { ApplicationManager.getApplication().runWriteAction( new ExternalChangeAction.ExternalDocumentChange(document, project) { + @Override public void run() { boolean wasWritable = document.isWritable(); DocumentEx documentEx = (DocumentEx)document; @@ -558,6 +582,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl builder.addOkAction().setText(UIBundle.message("file.cache.conflict.load.fs.changes.button")); builder.addCancelAction().setText(UIBundle.message("file.cache.conflict.keep.memory.changes.button")); builder.addAction(new AbstractAction(UIBundle.message("file.cache.conflict.show.difference.button")) { + @Override public void actionPerformed(ActionEvent e) { String windowtitle = UIBundle.message("file.cache.conflict.for.file.dialog.title", file.getPresentableUrl()); final ProjectEx project = (ProjectEx)ProjectLocator.getInstance().guessProjectForFile(file); @@ -591,6 +616,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl protected void reportErrorOnSave(final IOException e) { // invokeLater here prevents attempt to show dialog in write action ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override public void run() { Messages.showMessageDialog( UIBundle.message("cannot.save.file.with.error.error.message", e.getMessage()), @@ -601,9 +627,11 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl }); } + @Override public void fileCreated(VirtualFileEvent event) { } + @Override public void fileDeleted(VirtualFileEvent event) { Document doc = getCachedDocument(event.getFile()); if (doc != null) { @@ -611,22 +639,28 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl } } + @Override public void fileMoved(VirtualFileMoveEvent event) { } + @Override public void fileCopied(VirtualFileCopyEvent event) { fileCreated(event); } + @Override public void beforePropertyChange(VirtualFilePropertyEvent event) { } + @Override public void beforeContentsChange(VirtualFileEvent event) { } + @Override public void beforeFileDeletion(VirtualFileEvent event) { } + @Override public void beforeFileMovement(VirtualFileMoveEvent event) { } 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 fb4c6759109a..e56a68e89719 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 @@ -1647,6 +1647,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec if (newFilePair == null) continue; VirtualFile newFile = newFilePair.first; + if (newFile == null) continue; // already open if (eachWindow.findFileIndex(newFile) != -1) continue; diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ChooseActionsDialog.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ChooseActionsDialog.java index 2a668c4cb46c..072aea54019c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ChooseActionsDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ChooseActionsDialog.java @@ -19,41 +19,85 @@ */ package com.intellij.openapi.keymap.impl.ui; +import com.intellij.ide.CommonActionsManager; +import com.intellij.ide.TreeExpander; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.QuickList; +import com.intellij.openapi.keymap.KeyMapBundle; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.IconLoader; +import com.intellij.packageDependencies.ui.TreeExpansionMonitor; +import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.FilterComponent; +import com.intellij.util.Alarm; import com.intellij.util.ArrayUtil; +import com.intellij.util.IJSwingUtilities; +import com.intellij.util.ui.FormBuilder; +import com.intellij.util.ui.UIUtil; +import com.intellij.util.ui.tree.TreeUtil; import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.event.DocumentEvent; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.util.ArrayList; public class ChooseActionsDialog extends DialogWrapper { private final ActionsTree myActionsTree; + private FilterComponent myFilterComponent; + private TreeExpansionMonitor myTreeExpansionMonitor; + private Keymap myKeymap; + private QuickList[] myQuicklists; + private JBPopup myPopup; public ChooseActionsDialog(Component parent, Keymap keymap, QuickList[] quicklists) { super(parent, true); + myKeymap = keymap; + myQuicklists = quicklists; myActionsTree = new ActionsTree(); myActionsTree.reset(keymap, quicklists); myActionsTree.getTree().getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); + myActionsTree.getTree().addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + doOKAction(); + } + } + }); + + myTreeExpansionMonitor = TreeExpansionMonitor.install(myActionsTree.getTree()); + setTitle("Add Actions to Quick List"); init(); } + @Override + protected JComponent createNorthPanel() { + return createToolbarPanel(); + } + @Override protected JComponent createCenterPanel() { JPanel panel = new JPanel(new BorderLayout()); panel.add(myActionsTree.getComponent()); panel.setPreferredSize(new Dimension(400, 500)); - + return panel; } - + public String[] getTreeSelectedActionIds() { TreePath[] paths = myActionsTree.getTree().getSelectionPaths(); if (paths == null) return ArrayUtil.EMPTY_STRING_ARRAY; @@ -74,4 +118,160 @@ public class ChooseActionsDialog extends DialogWrapper { } return ArrayUtil.toStringArray(actions); } + + private JPanel createToolbarPanel() { + final JPanel panel = new JPanel(new BorderLayout()); + DefaultActionGroup group = new DefaultActionGroup(); + final JComponent toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true).getComponent(); + final CommonActionsManager commonActionsManager = CommonActionsManager.getInstance(); + final TreeExpander treeExpander = new TreeExpander() { + public void expandAll() { + TreeUtil.expandAll(myActionsTree.getTree()); + } + + public boolean canExpand() { + return true; + } + + public void collapseAll() { + TreeUtil.collapseAll(myActionsTree.getTree(), 0); + } + + public boolean canCollapse() { + return true; + } + }; + group.add(commonActionsManager.createExpandAllAction(treeExpander, myActionsTree.getTree())); + group.add(commonActionsManager.createCollapseAllAction(treeExpander, myActionsTree.getTree())); + + panel.add(toolbar, BorderLayout.WEST); + group = new DefaultActionGroup(); + final JComponent searchToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true).getComponent(); + final Alarm alarm = new Alarm(); + myFilterComponent = new FilterComponent("KEYMAP_IN_QUICK_LISTS", 5) { + public void filter() { + alarm.cancelAllRequests(); + alarm.addRequest(new Runnable() { + public void run() { + if (!myFilterComponent.isShowing()) return; + if (!myTreeExpansionMonitor.isFreeze()) myTreeExpansionMonitor.freeze(); + final String filter = getFilter(); + myActionsTree.filter(filter, myQuicklists); + final JTree tree = myActionsTree.getTree(); + TreeUtil.expandAll(tree); + if (filter == null || filter.length() == 0) { + TreeUtil.collapseAll(tree, 0); + myTreeExpansionMonitor.restore(); + } + } + }, 300); + } + }; + myFilterComponent.reset(); + + panel.add(myFilterComponent, BorderLayout.CENTER); + + group.add(new AnAction(KeyMapBundle.message("filter.shortcut.action.text"), + KeyMapBundle.message("filter.shortcut.action.text"), + IconLoader.getIcon("/ant/shortcutFilter.png")) { + public void actionPerformed(AnActionEvent e) { + myFilterComponent.reset(); + if (myPopup == null || myPopup.getContent() == null) { + myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(createFilteringPanel(), null) + .setRequestFocus(true) + .setTitle(KeyMapBundle.message("filter.settings.popup.title")) + .setMovable(true) + .createPopup(); + } + myPopup.showUnderneathOf(searchToolbar); + } + }); + group.add(new AnAction(KeyMapBundle.message("filter.clear.action.text"), + KeyMapBundle.message("filter.clear.action.text"), IconLoader.getIcon("/actions/gc.png")) { + public void actionPerformed(AnActionEvent e) { + myActionsTree.filter(null, myQuicklists); //clear filtering + TreeUtil.collapseAll(myActionsTree.getTree(), 0); + myTreeExpansionMonitor.restore(); + } + }); + + panel.add(searchToolbar, BorderLayout.EAST); + return panel; + } + + private void filterTreeByShortcut(final ShortcutTextField firstShortcut, + final JCheckBox enable2Shortcut, + final ShortcutTextField secondShortcut) { + final KeyStroke keyStroke = firstShortcut.getKeyStroke(); + if (keyStroke != null) { + if (!myTreeExpansionMonitor.isFreeze()) myTreeExpansionMonitor.freeze(); + myActionsTree.filterTree(new KeyboardShortcut(keyStroke, enable2Shortcut.isSelected() ? secondShortcut.getKeyStroke() : null), + myQuicklists); + final JTree tree = myActionsTree.getTree(); + TreeUtil.expandAll(tree); + } + } + + private JPanel createFilteringPanel() { + myActionsTree.reset(myKeymap, myQuicklists); + + final JLabel firstLabel = new JLabel(KeyMapBundle.message("filter.first.stroke.input")); + final JCheckBox enable2Shortcut = new JCheckBox(KeyMapBundle.message("filter.second.stroke.input")); + final ShortcutTextField firstShortcut = new ShortcutTextField(); + firstShortcut.setColumns(10); + final ShortcutTextField secondShortcut = new ShortcutTextField(); + secondShortcut.setColumns(10); + + enable2Shortcut.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + secondShortcut.setEnabled(enable2Shortcut.isSelected()); + if (enable2Shortcut.isSelected()) { + secondShortcut.requestFocusInWindow(); + } + } + }); + + firstShortcut.getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(DocumentEvent e) { + filterTreeByShortcut(firstShortcut, enable2Shortcut, secondShortcut); + } + }); + + secondShortcut.getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(DocumentEvent e) { + filterTreeByShortcut(firstShortcut, enable2Shortcut, secondShortcut); + } + }); + + IJSwingUtilities.adjustComponentsOnMac(firstLabel, firstShortcut); + JPanel filterComponent = FormBuilder.createFormBuilder() + .addLabeledComponent(firstLabel, firstShortcut, true) + .addComponent(enable2Shortcut) + .setVerticalGap(0) + .setIndent(5) + .addComponent(secondShortcut) + .getPanel(); + + filterComponent.setBorder(new EmptyBorder(UIUtil.PANEL_SMALL_INSETS)); + + enable2Shortcut.setSelected(false); + secondShortcut.setEnabled(false); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + firstShortcut.requestFocus(); + } + }); + return filterComponent; + } + + + public void dispose() { + super.dispose(); + if (myPopup != null && myPopup.isVisible()) { + myPopup.cancel(); + } + if (myFilterComponent != null) { + myFilterComponent.dispose(); + } + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java index a53ec8bed25b..6d223a185ef1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/KeymapPanel.java @@ -50,12 +50,16 @@ import com.intellij.ui.DocumentAdapter; import com.intellij.ui.FilterComponent; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.Alarm; +import com.intellij.util.IJSwingUtilities; import com.intellij.util.containers.HashMap; +import com.intellij.util.ui.FormBuilder; +import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import java.awt.*; import java.awt.event.*; @@ -119,7 +123,7 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi if (shortcuts != null) { for (Shortcut shortcut : shortcuts) { - impl.removeShortcut(actionId, shortcut); + impl.removeShortcut(actionId, shortcut); impl.addShortcut(newActionId, shortcut); } } @@ -270,7 +274,7 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi importButton.setMargin(insets); panel.add(importButton,gc); - + } @@ -376,7 +380,7 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi }; group.add(commonActionsManager.createExpandAllAction(treeExpander, myActionsTree.getTree())); group.add(commonActionsManager.createCollapseAllAction(treeExpander, myActionsTree.getTree())); - + group.add(new AnAction("Edit Shortcut", "Edit Shortcut", IconLoader.getIcon("/actions/properties.png")) { { registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)), myActionsTree.getTree()); @@ -459,40 +463,45 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi private JPanel createFilteringPanel() { myActionsTree.reset(getSelectedKeymap(), getCurrentQuickListIds()); - JPanel filterComponent = new JPanel(new GridBagLayout()); - filterComponent.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); + final JLabel firstLabel = new JLabel(KeyMapBundle.message("filter.first.stroke.input")); + final JCheckBox enable2Shortcut = new JCheckBox(KeyMapBundle.message("filter.second.stroke.input")); final ShortcutTextField firstShortcut = new ShortcutTextField(); final ShortcutTextField secondShortcut = new ShortcutTextField(); - final JCheckBox enable2Shortcut = new JCheckBox(KeyMapBundle.message("filter.enable.second.stroke.checkbox")); - firstShortcut.getDocument().addDocumentListener(new DocumentAdapter() { - protected void textChanged(DocumentEvent e) { - filterTreeByShortcut(firstShortcut, enable2Shortcut, secondShortcut); - } - }); - secondShortcut.getDocument().addDocumentListener(new DocumentAdapter() { - protected void textChanged(DocumentEvent e) { - filterTreeByShortcut(firstShortcut, enable2Shortcut, secondShortcut); - } - }); - final JLabel firstLabel = new JLabel(KeyMapBundle.message("filter.first.stroke.input")); - final JLabel secondLabel = new JLabel(KeyMapBundle.message("filter.second.stroke.input")); - filterComponent.add(firstLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(5,2,0,0),0,0)); - filterComponent.add(firstShortcut, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0,2,0,0),0,0)); + enable2Shortcut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { secondShortcut.setEnabled(enable2Shortcut.isSelected()); - secondLabel.setEnabled(enable2Shortcut.isSelected()); if (enable2Shortcut.isSelected()){ secondShortcut.requestFocusInWindow(); } } }); - filterComponent.add(enable2Shortcut, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0,0,0,0),0,0)); - filterComponent.add(secondLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0,2,0,0),0,0)); - filterComponent.add(secondShortcut, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0,2,0,0),0,0)); + + firstShortcut.getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(DocumentEvent e) { + filterTreeByShortcut(firstShortcut, enable2Shortcut, secondShortcut); + } + }); + + secondShortcut.getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(DocumentEvent e) { + filterTreeByShortcut(firstShortcut, enable2Shortcut, secondShortcut); + } + }); + + IJSwingUtilities.adjustComponentsOnMac(firstLabel, firstShortcut); + JPanel filterComponent = FormBuilder.createFormBuilder() + .addLabeledComponent(firstLabel, firstShortcut, true) + .addComponent(enable2Shortcut) + .setVerticalGap(0) + .setIndent(5) + .addComponent(secondShortcut) + .getPanel(); + + filterComponent.setBorder(new EmptyBorder(UIUtil.PANEL_SMALL_INSETS)); + enable2Shortcut.setSelected(false); - secondLabel.setEnabled(false); secondShortcut.setEnabled(false); SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -938,7 +947,7 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi DefaultActionGroup group = new DefaultActionGroup(); final Shortcut[] shortcuts = mySelectedKeymap.getShortcuts(actionId); - + group.add(new AnAction("Add Keyboard Shortcut") { @Override public void actionPerformed(AnActionEvent e) { @@ -953,7 +962,7 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi addKeyboardShortcut(firstKeyboard); } }); - + group.add(new AnAction("Add Mouse Shortcut") { @Override public void actionPerformed(AnActionEvent e) { @@ -991,7 +1000,7 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi dataContext, JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, true); - + if (e instanceof MouseEvent) { popup.show(new RelativePoint((MouseEvent)e)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java index 719dd5276cd4..ce5ad9dacc10 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java @@ -50,6 +50,7 @@ public class CheckForUpdateAction extends AnAction implements DumbAware { ProgressManager.getInstance().run(new Task.Modal(project, "Checking for updates", false) { @Override public void run(@NotNull ProgressIndicator indicator) { + indicator.setIndeterminate(true); final CheckForUpdateResult result = UpdateChecker.checkForUpdates(instance, PropertiesComponent.getInstance(), true ); diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java index 55440a7c90a8..75a7c922e459 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java @@ -329,6 +329,7 @@ public class PluginDownloader { if (fileName == null || !PathUtil.isValidFileName(fileName)) { FileUtil.delete(file); + LOG.warn("Invalid file name (header=" + contentDisposition + "; url=" + connection.getURL() + "; name=" + fileName + ")"); throw new IOException("Invalid filename returned by the server"); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerImpl.java index c1b580603cbd..fa98c84c896e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerImpl.java @@ -219,11 +219,13 @@ public class VirtualFilePointerImpl extends UserDataHolderBase implements Virtua disposed = true; final Pair pair = myFileAndUrl; - if (pair.first != null) { - ((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).clearPointerCaches(pair.first.getUrl(), myListener); + VirtualFile file = pair.first; + if (file != null) { + ((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).clearPointerCaches(file.getUrl(), myListener); } - if (pair.second != null) { - ((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).clearPointerCaches(pair.second, myListener); + String url = pair.second; + if (url != null && (file == null || !url.equals(file.getUrl()))) { + ((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).clearPointerCaches(url, myListener); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java index 15ec1b998201..6b9ac8d5ab93 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerManagerImpl.java @@ -72,7 +72,6 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp synchronized void clearPointerCaches(String url, VirtualFilePointerListener listener) { TreeMap urlToPointer = myUrlToPointerMaps.get(listener); - if (urlToPointer == null && ApplicationManager.getApplication().isUnitTestMode()) return; assert urlToPointer != null; urlToPointer.remove(VfsUtil.urlToPath(url)); if (urlToPointer.isEmpty()) { @@ -148,12 +147,6 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp return url.substring(separatorIndex + JarFileSystem.JAR_SEPARATOR.length()); } - @TestOnly - public synchronized void cleanupForNextTest() { - myUrlToPointerMaps.clear(); - myContainers.clear(); - } - /** * @see #create(String, com.intellij.openapi.Disposable, com.intellij.openapi.vfs.pointers.VirtualFilePointerListener) */ @@ -339,7 +332,7 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp VirtualFilePointerListener listener = entry.getKey(); TreeMap map = entry.getValue(); for (VirtualFilePointerImpl pointer : map.values()) { - myUrlToPointerMaps.clear(); + //myUrlToPointerMaps.clear(); pointer.throwNotDisposedError("Not disposed pointer: listener="+listener); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java index cc6e397f8e86..e1f9760bb1f8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/PositionPanel.java @@ -128,8 +128,11 @@ public class PositionPanel extends EditorBasedWidget implements StatusBarWidget. public void caretPositionChanged(final CaretEvent e) { final Editor editor = e.getEditor(); Project project = editor.getProject(); - if (project != null && !project.isDisposed() && FileEditorManager.getInstance(project).getSelectedTextEditor() == e.getEditor()) { - updatePosition(editor); + if (project != null && !project.isDisposed()) { + final FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); // returns null for default project + if (fileEditorManager != null && fileEditorManager.getSelectedTextEditor() == e.getEditor()) { + updatePosition(editor); + } } } diff --git a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java index b40e9ca29530..d902cbe95204 100644 --- a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java +++ b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java @@ -103,6 +103,11 @@ public class NewDirectoryProjectDialog extends DialogWrapper { setErrorText("Project name can't be empty"); return; } + if (myLocationField.getText().indexOf('$') >= 0) { + setOKActionEnabled(false); + setErrorText("Project directory name must not contain the $ character"); + return; + } DirectoryProjectGenerator generator = getProjectGenerator(); if (generator != null) { String baseDirPath = myLocationField.getTextField().getText(); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VirtualFilePointerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VirtualFilePointerTest.java index 116a6c59557c..ec9f7b074671 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VirtualFilePointerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VirtualFilePointerTest.java @@ -424,6 +424,39 @@ public class VirtualFilePointerTest extends PlatformLangTestCase { }); } + public void testDoubleDispose() throws IOException { + final File tempDir = createTempDirectory(); + final File file = new File(tempDir, "f1"); + boolean created = file.createNewFile(); + assertTrue(created); + + final VirtualFile[] vFile = new VirtualFile[1]; + final String url = VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, file.getCanonicalPath().replace(File.separatorChar, '/')); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + vFile[0] = VirtualFileManager.getInstance().refreshAndFindFileByUrl(url); + } + }); + + Disposable disposable = Disposer.newDisposable(); + final VirtualFilePointer pointer = myVirtualFilePointerManager.create(vFile[0], disposable, new VirtualFilePointerListener() { + @Override + public void beforeValidityChanged(VirtualFilePointer[] pointers) { + } + + @Override + public void validityChanged(VirtualFilePointer[] pointers) { + } + }); + + + assertTrue(pointer.isValid()); + + Disposer.dispose(disposable); + assertFalse(pointer.isValid()); + } + public void testThreads() throws IOException, InterruptedException { final File ioTempDir = createTempDirectory(); final File ioPtrBase = new File(ioTempDir, "parent"); diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index 01eca8e8d941..f4e051cf3f87 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -45,6 +45,7 @@ import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.editor.impl.EditorFactoryImpl; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl; @@ -335,6 +336,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da storeSettings(); myThreadTracker = new ThreadTracker(); + DocumentImpl.CHECK_DOCUMENT_CONSISTENCY = !isPerformanceTest(); } public static void doSetup(final LightProjectDescriptor descriptor, diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index 2a853d4ea32f..84a3123ea6cf 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -36,6 +36,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.event.DocumentListener; +import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.module.EmptyModuleType; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; @@ -53,11 +54,9 @@ import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl; import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl; import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; -import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; @@ -191,6 +190,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro } DocumentCommitThread.getInstance().clearQueue(); + DocumentImpl.CHECK_DOCUMENT_CONSISTENCY = !isPerformanceTest(); } public Project getProject() { @@ -339,10 +339,6 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro LocalHistoryImpl.getInstanceImpl().cleanupForNextTest(); - VirtualFilePointerManagerImpl virtualFilePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance(); - if (virtualFilePointerManager != null) { - virtualFilePointerManager.cleanupForNextTest(); - } PatchedWeakReference.clearAll(); } diff --git a/platform/util-rt/src/com/intellij/BundleBase.java b/platform/util-rt/src/com/intellij/BundleBase.java new file mode 100644 index 000000000000..566be37adda1 --- /dev/null +++ b/platform/util-rt/src/com/intellij/BundleBase.java @@ -0,0 +1,109 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij; + +import com.intellij.openapi.util.SystemInfoRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * @author yole + */ +public abstract class BundleBase { + public static final char MNEMONIC = 0x1B; + + public static boolean assertKeyIsFound = false; + + public static String messageOrDefault(@Nullable final ResourceBundle bundle, + final String key, + @Nullable final String defaultValue, + final Object... params) { + if (bundle == null) return defaultValue; + + String value; + try { + value = bundle.getString(key); + } + catch (MissingResourceException e) { + if (defaultValue != null) { + value = defaultValue; + } + else { + value = "!" + key + "!"; + if (assertKeyIsFound) { + assert false : key + " is not found in " + bundle; + } + } + } + + value = replaceMnemonicAmpersand(value); + + if (params.length > 0 && value.indexOf('{') >= 0) { + return MessageFormat.format(value, params); + } + + return value; + } + + @NotNull + public static String message(@NotNull ResourceBundle bundle, @NotNull String key, @NotNull Object... params) { + return messageOrDefault(bundle, key, null, params); + } + + public static String replaceMnemonicAmpersand(final String value) { + if (value.indexOf('&') >= 0) { + boolean useMacMnemonic = value.contains("&&"); + StringBuilder realValue = new StringBuilder(); + int i = 0; + while (i < value.length()) { + char c = value.charAt(i); + if (c == '\\') { + if (i < value.length() - 1 && value.charAt(i + 1) == '&') { + realValue.append('&'); + i++; + } + else { + realValue.append(c); + } + } + else if (c == '&') { + if (i < value.length() - 1 && value.charAt(i + 1) == '&') { + if (SystemInfoRt.isMac) { + realValue.append(MNEMONIC); + } + i++; + } + else { + if (!SystemInfoRt.isMac || !useMacMnemonic) { + realValue.append(MNEMONIC); + } + } + } + else { + realValue.append(c); + } + i++; + } + + return realValue.toString(); + } + return value; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrPostfixExpression.java b/platform/util-rt/src/com/intellij/execution/rmi/RemoteCastable.java similarity index 68% rename from plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrPostfixExpression.java rename to platform/util-rt/src/com/intellij/execution/rmi/RemoteCastable.java index de2bb73e0d4d..816cb32afc17 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrPostfixExpression.java +++ b/platform/util-rt/src/com/intellij/execution/rmi/RemoteCastable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -13,11 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package com.intellij.execution.rmi; -package org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions; +import java.rmi.Remote; +import java.rmi.RemoteException; /** - * @author ilyas + * @author Gregory.Shrago */ -public interface GrPostfixExpression extends GrUnaryExpression { +public interface RemoteCastable extends Remote { + String getCastToClassName() throws RemoteException; } diff --git a/platform/util/src/com/intellij/execution/rmi/RemoteObject.java b/platform/util-rt/src/com/intellij/execution/rmi/RemoteObject.java similarity index 92% rename from platform/util/src/com/intellij/execution/rmi/RemoteObject.java rename to platform/util-rt/src/com/intellij/execution/rmi/RemoteObject.java index 2a487832a849..859186d41bce 100644 --- a/platform/util/src/com/intellij/execution/rmi/RemoteObject.java +++ b/platform/util-rt/src/com/intellij/execution/rmi/RemoteObject.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -15,9 +15,9 @@ */ package com.intellij.execution.rmi; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import com.intellij.util.containers.ContainerUtilRt; import java.lang.ref.WeakReference; import java.rmi.Remote; @@ -45,7 +45,7 @@ public class RemoteObject implements Remote, Unreferenced { @Nullable public synchronized T export(@Nullable T child) throws RemoteException { if (child == null) return null; - final T result = (T)UnicastRemoteObject.exportObject(child, 0); + @SuppressWarnings("unchecked") final T result = (T)UnicastRemoteObject.exportObject(child, 0); myChildren.put((RemoteObject)child, result); ((RemoteObject)child).myParent = this; return result; @@ -68,7 +68,7 @@ public class RemoteObject implements Remote, Unreferenced { if (children.isEmpty()) return; final ArrayList list = new ArrayList(children.size()); for (WeakReference child : children) { - ContainerUtil.addIfNotNull(child.get(), list); + ContainerUtilRt.addIfNotNull(child.get(), list); } myChildren.keySet().removeAll(list); for (RemoteObject child : list) { @@ -85,6 +85,7 @@ public class RemoteObject implements Remote, Unreferenced { UnicastRemoteObject.unexportObject(this, false); } catch (RemoteException e) { + //noinspection CallToPrintStackTrace e.printStackTrace(); } } @@ -113,5 +114,4 @@ public class RemoteObject implements Remote, Unreferenced { protected boolean isKnownException(Throwable ex) { return false; } - } diff --git a/platform/util/src/com/intellij/execution/rmi/RemoteServer.java b/platform/util-rt/src/com/intellij/execution/rmi/RemoteServer.java similarity index 76% rename from platform/util/src/com/intellij/execution/rmi/RemoteServer.java rename to platform/util-rt/src/com/intellij/execution/rmi/RemoteServer.java index aa1b2100b0b7..9e846ea83a56 100644 --- a/platform/util/src/com/intellij/execution/rmi/RemoteServer.java +++ b/platform/util-rt/src/com/intellij/execution/rmi/RemoteServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -15,8 +15,9 @@ */ package com.intellij.execution.rmi; +import org.jetbrains.annotations.Nullable; + import javax.naming.Context; -import javax.naming.InitialContext; import javax.naming.NamingException; import javax.naming.spi.InitialContextFactory; import java.lang.reflect.InvocationHandler; @@ -32,18 +33,17 @@ import java.util.Random; public class RemoteServer { private static Remote ourRemote; - private static Remote ourStub; + @SuppressWarnings("UseOfSystemOutOrSystemErr") protected static void start(Remote remote) throws Exception { setupRMI(); banJNDI(); if (ourRemote != null) throw new AssertionError("Already started"); - ourRemote = remote; Registry registry; - int port = 0; + int port; for (Random random = new Random(); ;) { port = random.nextInt(0xffff); if (port < 4000) continue; @@ -51,22 +51,23 @@ public class RemoteServer { registry = LocateRegistry.createRegistry(port); break; } - catch (ExportException ex) { - } + catch (ExportException ignored) { } } - try { - ourStub = UnicastRemoteObject.exportObject(ourRemote, 0); - final String name = remote.getClass().getSimpleName() + Integer.toHexString(ourStub.hashCode()); - registry.bind(name, ourStub); - System.out.println("Port/ID:" + port + "/" + name); + try { + Remote stub = UnicastRemoteObject.exportObject(ourRemote, 0); + final String name = remote.getClass().getSimpleName() + Integer.toHexString(stub.hashCode()); + registry.bind(name, stub); + + System.out.println("Port/ID: " + port + "/" + name); + Object lock = new Object(); synchronized (lock) { lock.wait(); } } catch (Throwable e) { - e.printStackTrace(); + e.printStackTrace(System.err); System.exit(1); } } @@ -77,23 +78,24 @@ public class RemoteServer { // do not use domain or http address for server System.setProperty("java.rmi.server.hostname", "localhost"); - // do not use http tunnelling + // do not use HTTP tunnelling System.setProperty("java.rmi.server.disableHttp", "true"); } private static void banJNDI() { - if (System.getProperty(InitialContext.INITIAL_CONTEXT_FACTORY) == null) { - System.setProperty(InitialContext.INITIAL_CONTEXT_FACTORY, "com.intellij.execution.rmi.RemoteServer$Jndi"); + if (System.getProperty(Context.INITIAL_CONTEXT_FACTORY) == null) { + System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.intellij.execution.rmi.RemoteServer$Jndi"); } } + @SuppressWarnings("UnusedDeclaration") public static class Jndi implements InitialContextFactory, InvocationHandler { - @Override public Context getInitialContext(final Hashtable environment) throws NamingException { - return (Context) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Context.class}, this ); + return (Context)Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Context.class}, this); } + @Nullable @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return null; diff --git a/platform/util-rt/src/com/intellij/openapi/diagnostic/rt/Logger.java b/platform/util-rt/src/com/intellij/openapi/diagnostic/rt/Logger.java new file mode 100644 index 000000000000..8eb116e18585 --- /dev/null +++ b/platform/util-rt/src/com/intellij/openapi/diagnostic/rt/Logger.java @@ -0,0 +1,161 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.diagnostic.rt; + +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Method; +import java.util.logging.Level; +import java.util.logging.LogManager; + +/** + * A wrapper which uses either IDE logging subsystem (if available) or java.util.logging. + * + * @since 12.0 + */ +public abstract class Logger { + private interface Factory { + Logger getInstance(@NotNull @NonNls final String category); + } + + private static Factory ourFactory; + + private synchronized static Factory getFactory() { + if (ourFactory == null) { + try { + ourFactory = new IdeaFactory(); + } + catch (Throwable t) { + ourFactory = new JavaFactory(); + } + } + return ourFactory; + } + + @NotNull + public static Logger getInstance(@NotNull @NonNls final String category) { + return getFactory().getInstance(category); + } + + public void info(@Nullable @NonNls final String message) { + info(message, null); + } + + public void info(@NotNull final Throwable t) { + info(t.getMessage(), t); + } + + public void warn(@Nullable @NonNls final String message) { + warn(message, null); + } + + public void warn(@NotNull final Throwable t) { + warn(t.getMessage(), t); + } + + public void error(@Nullable @NonNls final String message) { + error(message, null); + } + + public void error(@NotNull final Throwable t) { + error(t.getMessage(), t); + } + + public abstract void info(@Nullable @NonNls final String message, @Nullable final Throwable t); + public abstract void warn(@Nullable @NonNls final String message, @Nullable final Throwable t); + public abstract void error(@Nullable @NonNls final String message, @Nullable final Throwable t); + + private static class JavaFactory implements Factory { + private final LogManager myManager = LogManager.getLogManager(); + + @Override + public Logger getInstance(@NotNull @NonNls final String category) { + final java.util.logging.Logger logger = myManager.getLogger(category); + return new Logger() { + @Override + public void info(@Nullable @NonNls final String message, @Nullable final Throwable t) { + logger.log(Level.INFO, message, t); + } + + @Override + public void warn(@Nullable @NonNls final String message, @Nullable final Throwable t) { + logger.log(Level.WARNING, message, t); + } + + @Override + public void error(@Nullable @NonNls final String message, @Nullable final Throwable t) { + logger.log(Level.SEVERE, message, t); + } + }; + } + } + + private static class IdeaFactory implements Factory { + private final Method myGetInstance; + private final Method myInfo; + private final Method myWarn; + private final Method myError; + + private IdeaFactory() throws Exception { + final Class loggerClass = Class.forName("com.intellij.openapi.diagnostic.Logger"); + myGetInstance = loggerClass.getMethod("getInstance", String.class); + myGetInstance.setAccessible(true); + myInfo = loggerClass.getMethod("info", String.class, Throwable.class); + myInfo.setAccessible(true); + myWarn = loggerClass.getMethod("warn", String.class, Throwable.class); + myInfo.setAccessible(true); + myError = loggerClass.getMethod("error", String.class, Throwable.class); + myError.setAccessible(true); + } + + @Override + public Logger getInstance(@NotNull @NonNls final String category) { + try { + final Object logger = myGetInstance.invoke(null, category); + return new Logger() { + @Override + public void info(@Nullable @NonNls final String message, @Nullable final Throwable t) { + try { + myInfo.invoke(logger, message, t); + } + catch (Exception ignored) { } + } + + @Override + public void warn(@Nullable @NonNls final String message, @Nullable final Throwable t) { + try { + myWarn.invoke(logger, message, t); + } + catch (Exception ignored) { } + } + + @Override + public void error(@Nullable @NonNls final String message, @Nullable final Throwable t) { + try { + myError.invoke(logger, message, t); + } + catch (Exception ignored) { } + } + }; + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/platform/util/src/com/intellij/openapi/util/Comparing.java b/platform/util-rt/src/com/intellij/openapi/util/Comparing.java similarity index 94% rename from platform/util/src/com/intellij/openapi/util/Comparing.java rename to platform/util-rt/src/com/intellij/openapi/util/Comparing.java index 95f5f8ab166a..95c7d6df8676 100644 --- a/platform/util/src/com/intellij/openapi/util/Comparing.java +++ b/platform/util-rt/src/com/intellij/openapi/util/Comparing.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -15,7 +15,7 @@ */ package com.intellij.openapi.util; -import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.util.text.StringUtilRt; import java.util.Arrays; import java.util.Collection; @@ -77,7 +77,7 @@ public class Comparing { if (c1 == c2) { continue; } - if (!caseSensitive && StringUtil.charsEqualIgnoreCase(c1, c2)) continue; + if (!caseSensitive && StringUtilRt.charsEqualIgnoreCase(c1, c2)) continue; return false; } @@ -140,6 +140,10 @@ public class Comparing { return o1 < o2 ? -1 : o1 == o2 ? 0 : 1; } + public static int compare(boolean o1, boolean o2) { + return o1 == o2 ? 0 : o1 ? 1 : -1; + } + public static int compare(int o1, int o2) { return o1 < o2 ? -1 : o1 == o2 ? 0 : 1; } diff --git a/platform/util/src/com/intellij/openapi/util/Pair.java b/platform/util-rt/src/com/intellij/openapi/util/Pair.java similarity index 98% rename from platform/util/src/com/intellij/openapi/util/Pair.java rename to platform/util-rt/src/com/intellij/openapi/util/Pair.java index d380de5a044a..ce63e207fcfa 100644 --- a/platform/util/src/com/intellij/openapi/util/Pair.java +++ b/platform/util-rt/src/com/intellij/openapi/util/Pair.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -18,7 +18,6 @@ package com.intellij.openapi.util; import com.intellij.util.Function; import org.jetbrains.annotations.Nullable; - public class Pair { public final A first; public final B second; diff --git a/platform/util-rt/src/com/intellij/openapi/util/SystemInfoRt.java b/platform/util-rt/src/com/intellij/openapi/util/SystemInfoRt.java new file mode 100644 index 000000000000..cdce6e247e32 --- /dev/null +++ b/platform/util-rt/src/com/intellij/openapi/util/SystemInfoRt.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.util; + +/** + * Stripped-down version of {@code com.intellij.openapi.util.SystemInfo}. + * Intended to use by external (out-of-IDE-process) runners and helpers so it should not contain any library dependencies. + * + * @since 12.0 + */ +@SuppressWarnings({"HardCodedStringLiteral", "UtilityClassWithoutPrivateConstructor"}) +public class SystemInfoRt { + public static final String OS_NAME = System.getProperty("os.name"); + public static final String OS_VERSION = System.getProperty("os.version").toLowerCase(); + + protected static final String _OS_NAME = OS_NAME.toLowerCase(); + public static final boolean isWindows = _OS_NAME.startsWith("windows"); + public static final boolean isOS2 = _OS_NAME.startsWith("os/2") || _OS_NAME.startsWith("os2"); + public static final boolean isMac = _OS_NAME.startsWith("mac"); + public static final boolean isLinux = _OS_NAME.startsWith("linux"); + public static final boolean isUnix = !isWindows && !isOS2; + + public static final boolean isFileSystemCaseSensitive = !isWindows && !isOS2 && !isMac; +} diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtilLight.java b/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java similarity index 74% rename from platform/util/src/com/intellij/openapi/util/io/FileUtilLight.java rename to platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java index ae174b7901d7..ff77c63af49c 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtilLight.java +++ b/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java @@ -15,9 +15,9 @@ */ package com.intellij.openapi.util.io; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.diagnostic.rt.Logger; +import com.intellij.openapi.util.SystemInfoRt; +import com.intellij.openapi.util.text.StringUtilRt; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,14 +27,22 @@ import java.io.*; import java.util.UUID; /** - * This is a light version of {@link FileUtil}. - * It is used by scripts loaded externally and almost independent of IDEA, so add here as few dependencies as possible. + * Stripped-down version of {@code com.intellij.openapi.util.io.FileUtil}. + * Intended to use by external (out-of-IDE-process) runners and helpers so it should not contain any library dependencies. + * + * @since 12.0 */ -public class FileUtilLight { - - private static String ourCanonicalTempPathCache = null; +@SuppressWarnings({"UtilityClassWithoutPrivateConstructor"}) +public class FileUtilRt { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.io.FileUtilLight"); + protected static final ThreadLocal BUFFER = new ThreadLocal() { + protected byte[] initialValue() { + return new byte[1024 * 20]; + } + }; + + private static String ourCanonicalTempPathCache = null; @NotNull public static File createTempDirectory(@NotNull @NonNls String prefix, @Nullable @NonNls String suffix) throws IOException { @@ -55,8 +63,7 @@ public class FileUtilLight { } @NotNull - public static File createTempFile(@NonNls final File dir, @NotNull @NonNls String prefix, @Nullable @NonNls String suffix, final boolean create) - throws IOException { + public static File createTempFile(@NonNls File dir, @NotNull @NonNls String prefix, @Nullable @NonNls String suffix, boolean create) throws IOException { return createTempFile(dir, prefix, suffix, create, true); } @@ -122,7 +129,7 @@ public class FileUtilLight { private static File normalizeFile(File temp) throws IOException { final File canonical = temp.getCanonicalFile(); - return SystemInfo.isWindows && canonical.getAbsolutePath().contains(" ") ? temp.getAbsoluteFile() : canonical; + return SystemInfoRt.isWindows && canonical.getAbsolutePath().contains(" ") ? temp.getAbsoluteFile() : canonical; } public static String getTempDirectory() { @@ -136,7 +143,7 @@ public class FileUtilLight { final File file = new File(System.getProperty("java.io.tmpdir")); try { final String canonical = file.getCanonicalPath(); - if (!SystemInfo.isWindows || !canonical.contains(" ")) { + if (!SystemInfoRt.isWindows || !canonical.contains(" ")) { return canonical; } } @@ -169,7 +176,7 @@ public class FileUtilLight { * * @param path the path to use * @param executableFlag new value of executable attribute - * @throws IOException if there is a problem with setting the flag + * @throws java.io.IOException if there is a problem with setting the flag */ public static void setExecutableAttribute(@NotNull String path, boolean executableFlag) throws IOException { final File file = new File(path); @@ -189,14 +196,14 @@ public class FileUtilLight { } @NotNull - public static String loadFile(@NotNull File file, String encoding) throws IOException { + public static String loadFile(@NotNull File file, @Nullable @NonNls String encoding) throws IOException { return loadFile(file, encoding, false); } @NotNull - public static String loadFile(@NotNull File file, String encoding, boolean convertLineSeparators) throws IOException { + public static String loadFile(@NotNull File file, @Nullable @NonNls String encoding, boolean convertLineSeparators) throws IOException { final String s = new String(loadFileText(file, encoding)); - return convertLineSeparators ? StringUtil.convertLineSeparators(s) : s; + return convertLineSeparators ? StringUtilRt.convertLineSeparators(s) : s; } @NotNull @@ -205,8 +212,9 @@ public class FileUtilLight { } @NotNull - public static char[] loadFileText(@NotNull File file, @NonNls String encoding) throws IOException { + public static char[] loadFileText(@NotNull File file, @Nullable @NonNls String encoding) throws IOException { InputStream stream = new FileInputStream(file); + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") Reader reader = encoding == null ? new InputStreamReader(stream) : new InputStreamReader(stream, encoding); try { return loadText(reader, (int)file.length()); @@ -235,4 +243,29 @@ public class FileUtilLight { } } + @NotNull + public static byte[] loadBytes(@NotNull InputStream stream) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + final byte[] bytes = BUFFER.get(); + while (true) { + int n = stream.read(bytes, 0, bytes.length); + if (n <= 0) break; + buffer.write(bytes, 0, n); + } + buffer.close(); + return buffer.toByteArray(); + } + + @NotNull + public static byte[] loadBytes(@NotNull InputStream stream, int length) throws IOException { + byte[] bytes = new byte[length]; + int count = 0; + while (count < length) { + int n = stream.read(bytes, count, length - count); + if (n <= 0) break; + count += n; + } + return bytes; + } + } diff --git a/platform/util-rt/src/com/intellij/openapi/util/text/StringUtilRt.java b/platform/util-rt/src/com/intellij/openapi/util/text/StringUtilRt.java new file mode 100644 index 000000000000..9b98436709b8 --- /dev/null +++ b/platform/util-rt/src/com/intellij/openapi/util/text/StringUtilRt.java @@ -0,0 +1,187 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.util.text; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Stripped-down version of {@code com.intellij.openapi.util.text.StringUtil}. + * Intended to use by external (out-of-IDE-process) runners and helpers so it should not contain any library dependencies. + * + * @since 12.0 + */ +@SuppressWarnings({"UtilityClassWithoutPrivateConstructor"}) +public class StringUtilRt { + public static boolean charsEqualIgnoreCase(char a, char b) { + return a == b || toUpperCase(a) == toUpperCase(b) || toLowerCase(a) == toLowerCase(b); + } + + public static char toUpperCase(char a) { + if (a < 'a') { + return a; + } + if (a >= 'a' && a <= 'z') { + return (char)(a + ('A' - 'a')); + } + return Character.toUpperCase(a); + } + + public static char toLowerCase(final char a) { + if (a < 'A' || a >= 'a' && a <= 'z') { + return a; + } + + if (a >= 'A' && a <= 'Z') { + return (char)(a + ('a' - 'A')); + } + + return Character.toLowerCase(a); + } + + /** + * Converts line separators to "\n" + */ + @NotNull + public static String convertLineSeparators(@NotNull String text) { + return convertLineSeparators(text, false); + } + + @NotNull + public static String convertLineSeparators(@NotNull String text, boolean keepCarriageReturn) { + return convertLineSeparators(text, "\n", null, keepCarriageReturn); + } + + @NotNull + public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator) { + return convertLineSeparators(text, newSeparator, null); + } + + @NotNull + public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator, @Nullable int[] offsetsToKeep) { + return convertLineSeparators(text, newSeparator, offsetsToKeep, false); + } + + @NotNull + public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator, @Nullable int[] offsetsToKeep, + boolean keepCarriageReturn) { + StringBuilder buffer = null; + int intactLength = 0; + final boolean newSeparatorIsSlashN = "\n".equals(newSeparator); + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + if (c == '\n') { + if (!newSeparatorIsSlashN) { + if (buffer == null) { + buffer = new StringBuilder(text.length()); + buffer.append(text, 0, intactLength); + } + buffer.append(newSeparator); + shiftOffsets(offsetsToKeep, buffer.length(), 1, newSeparator.length()); + } + else if (buffer == null) { + intactLength++; + } + else { + buffer.append(c); + } + } + else if (c == '\r') { + boolean followedByLineFeed = i < text.length() - 1 && text.charAt(i + 1) == '\n'; + if (!followedByLineFeed && keepCarriageReturn) { + if (buffer == null) { + intactLength++; + } + else { + buffer.append(c); + } + continue; + } + if (buffer == null) { + buffer = new StringBuilder(text.length()); + buffer.append(text, 0, intactLength); + } + buffer.append(newSeparator); + if (followedByLineFeed) { + //noinspection AssignmentToForLoopParameter + i++; + shiftOffsets(offsetsToKeep, buffer.length(), 2, newSeparator.length()); + } + else { + shiftOffsets(offsetsToKeep, buffer.length(), 1, newSeparator.length()); + } + } + else { + if (buffer == null) { + intactLength++; + } + else { + buffer.append(c); + } + } + } + return buffer == null ? text : buffer.toString(); + } + + private static void shiftOffsets(int[] offsets, int changeOffset, int oldLength, int newLength) { + if (offsets == null) return; + int shift = newLength - oldLength; + if (shift == 0) return; + for (int i = 0; i < offsets.length; i++) { + int offset = offsets[i]; + if (offset >= changeOffset + oldLength) { + offsets[i] += shift; + } + } + } + + public static int parseInt(final String string, final int defaultValue) { + try { + return Integer.parseInt(string); + } + catch (Exception e) { + return defaultValue; + } + } + + public static double parseDouble(final String string, final double defaultValue) { + try { + return Double.parseDouble(string); + } + catch (Exception e) { + return defaultValue; + } + } + + @NotNull + public static String getShortName(@NotNull Class aClass) { + return getShortName(aClass.getName()); + } + + @NotNull + public static String getShortName(@NotNull String fqName) { + return getShortName(fqName, '.'); + } + + @NotNull + public static String getShortName(@NotNull String fqName, char separator) { + int lastPointIdx = fqName.lastIndexOf(separator); + if (lastPointIdx >= 0) { + return fqName.substring(lastPointIdx + 1); + } + return fqName; + } +} diff --git a/platform/util-rt/src/com/intellij/util/ArrayUtilRt.java b/platform/util-rt/src/com/intellij/util/ArrayUtilRt.java new file mode 100644 index 000000000000..c898e0149572 --- /dev/null +++ b/platform/util-rt/src/com/intellij/util/ArrayUtilRt.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util; + +import org.jetbrains.annotations.NotNull; +import com.intellij.util.containers.ContainerUtilRt; + +import java.io.File; +import java.util.Collection; + +/** + * Stripped-down version of {@code com.intellij.util.ArrayUtil}. + * Intended to use by external (out-of-IDE-process) runners and helpers so it should not contain any library dependencies. + * + * @since 12.0 + */ +@SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "SSBasedInspection"}) +public class ArrayUtilRt { + public static final short[] EMPTY_SHORT_ARRAY = new short[0]; + public static final char[] EMPTY_CHAR_ARRAY = new char[0]; + public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + public static final int[] EMPTY_INT_ARRAY = new int[0]; + public static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0]; + public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + public static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + public static final long[] EMPTY_LONG_ARRAY = new long[0]; + public static final Collection[] EMPTY_COLLECTION_ARRAY = new Collection[0]; + public static final File[] EMPTY_FILE_ARRAY = new File[0]; + public static final Runnable[] EMPTY_RUNNABLE_ARRAY = new Runnable[0]; + + @NotNull + public static String[] toStringArray(@NotNull Collection collection) { + if (collection.isEmpty()) return EMPTY_STRING_ARRAY; + return ContainerUtilRt.toArray(collection, new String[collection.size()]); + } +} diff --git a/platform/util/src/com/intellij/util/Function.java b/platform/util-rt/src/com/intellij/util/Function.java similarity index 94% rename from platform/util/src/com/intellij/util/Function.java rename to platform/util-rt/src/com/intellij/util/Function.java index 089895796a25..fef2a94aaf2d 100644 --- a/platform/util/src/com/intellij/util/Function.java +++ b/platform/util-rt/src/com/intellij/util/Function.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -15,8 +15,6 @@ */ package com.intellij.util; -import org.jetbrains.annotations.Nullable; - import java.util.Collection; /** diff --git a/platform/util/src/com/intellij/util/NotNullFunction.java b/platform/util-rt/src/com/intellij/util/NotNullFunction.java similarity index 95% rename from platform/util/src/com/intellij/util/NotNullFunction.java rename to platform/util-rt/src/com/intellij/util/NotNullFunction.java index cae730360bd4..802172e3e5c4 100644 --- a/platform/util/src/com/intellij/util/NotNullFunction.java +++ b/platform/util-rt/src/com/intellij/util/NotNullFunction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/util/src/com/intellij/util/NullableFunction.java b/platform/util-rt/src/com/intellij/util/NullableFunction.java similarity index 95% rename from platform/util/src/com/intellij/util/NullableFunction.java rename to platform/util-rt/src/com/intellij/util/NullableFunction.java index a57e9b5dff17..ed768ae3ef7a 100644 --- a/platform/util/src/com/intellij/util/NullableFunction.java +++ b/platform/util-rt/src/com/intellij/util/NullableFunction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java b/platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java new file mode 100644 index 000000000000..7716a6d7d050 --- /dev/null +++ b/platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java @@ -0,0 +1,148 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util.containers; + +import com.intellij.util.ArrayUtilRt; +import com.intellij.util.Function; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Stripped-down version of {@code com.intellij.util.containers.ContainerUtil}. + * Intended to use by external (out-of-IDE-process) runners and helpers so it should not contain any library dependencies. + * + * @since 12.0 + */ +@SuppressWarnings({"UtilityClassWithoutPrivateConstructor"}) +public class ContainerUtilRt { + private static final int ARRAY_COPY_THRESHOLD = 20; + + /** + * Optimized toArray() as opposed to the {@link java.util.Collections#emptyList()}. + */ + private static class EmptyList extends AbstractList implements RandomAccess { + private static final EmptyList INSTANCE = new EmptyList(); + + public int size() { + return 0; + } + + public boolean contains(Object obj) { + return false; + } + + public Object get(int index) { + throw new IndexOutOfBoundsException("Index: " + index); + } + + @Override + public Object[] toArray() { + return ArrayUtilRt.EMPTY_OBJECT_ARRAY; + } + + @Override + public T[] toArray(T[] a) { + return a; + } + } + + @NotNull + public static List emptyList() { + @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) final List list = (List)EmptyList.INSTANCE; + return list; + } + + @NotNull + public static CopyOnWriteArrayList createEmptyCOWList() { + // does not create garbage new Object[0] + return new CopyOnWriteArrayList(ContainerUtilRt.emptyList()); + } + + public static void addIfNotNull(final T element, @NotNull Collection result) { + if (element != null) { + result.add(element); + } + } + + public static void addIfNotNull(@NotNull Collection result, @Nullable final T element) { + if (element != null) { + result.add(element); + } + } + + @NotNull + public static List map2List(@NotNull T[] array, @NotNull Function mapper) { + return map2List(Arrays.asList(array), mapper); + } + + @NotNull + public static List map2List(@NotNull Collection collection, @NotNull Function mapper) { + final ArrayList list = new ArrayList(collection.size()); + for (final T t : collection) { + list.add(mapper.fun(t)); + } + return list; + } + + @NotNull + public static Set map2Set(@NotNull T[] collection, @NotNull Function mapper) { + return map2Set(Arrays.asList(collection), mapper); + } + + @NotNull + public static Set map2Set(@NotNull Collection collection, @NotNull Function mapper) { + final HashSet set = new HashSet(collection.size()); + for (final T t : collection) { + set.add(mapper.fun(t)); + } + return set; + } + + @NotNull + public static T[] toArray(@NotNull List collection, @NotNull T[] array) { + final int length = array.length; + if (length < ARRAY_COPY_THRESHOLD) { + for (int i = 0; i < collection.size(); i++) { + array[i] = collection.get(i); + } + return array; + } + else { + return collection.toArray(array); + } + } + + /** + * This is a replacement for {@link Collection#toArray(Object[])}. For small collections it is faster to stay at java level and refrain + * from calling JNI {@link System#arraycopy(Object, int, Object, int, int)} + */ + @NotNull + public static T[] toArray(@NotNull Collection c, @NotNull T[] sample) { + final int size = c.size(); + if (size == sample.length && size < ARRAY_COPY_THRESHOLD) { + int i = 0; + for (T t : c) { + sample[i++] = t; + } + return sample; + } + + return c.toArray(sample); + } +} diff --git a/platform/util/src/com/intellij/util/io/LimitedInputStream.java b/platform/util-rt/src/com/intellij/util/io/LimitedInputStream.java similarity index 89% rename from platform/util/src/com/intellij/util/io/LimitedInputStream.java rename to platform/util-rt/src/com/intellij/util/io/LimitedInputStream.java index c18bdbe9f777..bc0f868a83a4 100644 --- a/platform/util/src/com/intellij/util/io/LimitedInputStream.java +++ b/platform/util-rt/src/com/intellij/util/io/LimitedInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -53,10 +53,10 @@ public class LimitedInputStream extends FilterInputStream { len = Math.min(len, myReadLimit - myBytesRead); if (len <= 0) return -1; - final int acutallyRead = super.read(b, off, len); - if (acutallyRead >= 0) myBytesRead += acutallyRead; + final int actuallyRead = super.read(b, off, len); + if (actuallyRead >= 0) myBytesRead += actuallyRead; - return acutallyRead; + return actuallyRead; } public long skip(long n) throws IOException { @@ -72,7 +72,7 @@ public class LimitedInputStream extends FilterInputStream { return Math.min(super.available(), myReadLimit - myBytesRead); } - public synchronized void mark(final int readlimit) { + public synchronized void mark(final int readLimit) { throw new UnsupportedOperationException(); } diff --git a/platform/util-rt/util-rt.iml b/platform/util-rt/util-rt.iml new file mode 100644 index 000000000000..4d3f06e41375 --- /dev/null +++ b/platform/util-rt/util-rt.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/platform/util/src/com/intellij/CommonBundle.java b/platform/util/src/com/intellij/CommonBundle.java index 19a540d3ae6f..941ce72fdd19 100644 --- a/platform/util/src/com/intellij/CommonBundle.java +++ b/platform/util/src/com/intellij/CommonBundle.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,25 +16,22 @@ package com.intellij; -import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.PropertyKey; import java.lang.ref.Reference; import java.lang.ref.SoftReference; -import java.text.MessageFormat; -import java.util.MissingResourceException; import java.util.ResourceBundle; /** * @author yole */ -public class CommonBundle { +public class CommonBundle extends BundleBase { + public static boolean assertKeyIsFound = false; + @NonNls private static final String BUNDLE = "messages.CommonBundle"; private static Reference ourBundle; - public static boolean assertKeyIsFound = false; private CommonBundle() {} @@ -53,38 +50,6 @@ public class CommonBundle { return bundle; } - public static String messageOrDefault(@Nullable final ResourceBundle bundle, final String key, @Nullable final String defaultValue, final Object... params) { - if (bundle == null) return defaultValue; - - String value; - try { - value = bundle.getString(key); - } - catch (MissingResourceException e) { - if (defaultValue != null) { - value = defaultValue; - } else { - value = "!" + key + "!"; - if (assertKeyIsFound) { - assert false: key + " is not found in "+BUNDLE; - } - } - } - - value = UIUtil.replaceMnemonicAmpersand(value); - - if (params.length > 0 && value.indexOf('{')>=0) { - return MessageFormat.format(value, params); - } - - return value; - } - - @NotNull - public static String message(@NotNull ResourceBundle bundle, @NotNull String key, @NotNull Object... params) { - return messageOrDefault(bundle, key, null, params); - } - @NotNull public static String getCancelButtonText() { return message("button.cancel"); @@ -142,5 +107,4 @@ public class CommonBundle { public static String getApplyButtonText() { return message("button.apply"); } - } diff --git a/platform/util/src/com/intellij/execution/rmi/RemoteCastable.java b/platform/util/src/com/intellij/execution/rmi/RemoteCastable.java deleted file mode 100644 index 28395a18b04d..000000000000 --- a/platform/util/src/com/intellij/execution/rmi/RemoteCastable.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.intellij.execution.rmi; - -import java.rmi.Remote; -import java.rmi.RemoteException; - -/** - * @author Gregory.Shrago - */ -public interface RemoteCastable extends Remote { - String getCastToClassName() throws RemoteException; -} diff --git a/platform/util/src/com/intellij/execution/rmi/RemoteUtil.java b/platform/util/src/com/intellij/execution/rmi/RemoteUtil.java index e98026215195..5ca43ada3991 100644 --- a/platform/util/src/com/intellij/execution/rmi/RemoteUtil.java +++ b/platform/util/src/com/intellij/execution/rmi/RemoteUtil.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.execution.rmi; import com.intellij.openapi.util.Pair; diff --git a/platform/util/src/com/intellij/openapi/util/SystemInfo.java b/platform/util/src/com/intellij/openapi/util/SystemInfo.java index a72b268f74cb..4022b3210a61 100644 --- a/platform/util/src/com/intellij/openapi/util/SystemInfo.java +++ b/platform/util/src/com/intellij/openapi/util/SystemInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -22,17 +22,16 @@ import java.io.File; import java.util.List; @SuppressWarnings({"HardCodedStringLiteral", "UtilityClassWithoutPrivateConstructor", "UnusedDeclaration"}) -public class SystemInfo { - public static final String OS_NAME = System.getProperty("os.name"); - public static final String OS_VERSION = System.getProperty("os.version").toLowerCase(); +public class SystemInfo extends SystemInfoRt { + public static final String OS_NAME = SystemInfoRt.OS_NAME; + public static final String OS_VERSION = SystemInfoRt.OS_VERSION; public static final String OS_ARCH = System.getProperty("os.arch"); public static final String JAVA_VERSION = System.getProperty("java.version"); public static final String JAVA_RUNTIME_VERSION = System.getProperty("java.runtime.version"); public static final String ARCH_DATA_MODEL = System.getProperty("sun.arch.data.model"); public static final String SUN_DESKTOP = System.getProperty("sun.desktop", ""); - private static final String _OS_NAME = OS_NAME.toLowerCase(); - public static final boolean isWindows = _OS_NAME.startsWith("windows"); + public static final boolean isWindows = SystemInfoRt.isWindows; public static final boolean isWindowsNT = _OS_NAME.startsWith("windows nt"); public static final boolean isWindows2000 = _OS_NAME.startsWith("windows 2000"); public static final boolean isWindows2003 = _OS_NAME.startsWith("windows 2003"); @@ -40,12 +39,12 @@ public class SystemInfo { public static final boolean isWindowsVista = _OS_NAME.startsWith("windows vista"); public static final boolean isWindows7 = _OS_NAME.startsWith("windows 7"); public static final boolean isWindows9x = _OS_NAME.startsWith("windows 9") || _OS_NAME.startsWith("windows me"); - public static final boolean isOS2 = _OS_NAME.startsWith("os/2") || _OS_NAME.startsWith("os2"); - public static final boolean isMac = _OS_NAME.startsWith("mac"); + public static final boolean isOS2 = SystemInfoRt.isOS2; + public static final boolean isMac = SystemInfoRt.isMac; + public static final boolean isLinux = SystemInfoRt.isLinux; public static final boolean isFreeBSD = _OS_NAME.startsWith("freebsd"); - public static final boolean isLinux = _OS_NAME.startsWith("linux"); public static final boolean isSolaris = _OS_NAME.startsWith("sunos"); - public static final boolean isUnix = !isWindows && !isOS2; + public static final boolean isUnix = SystemInfoRt.isUnix; private static final String _SUN_DESKTOP = SUN_DESKTOP.toLowerCase(); public static final boolean isKDE = _SUN_DESKTOP.contains("kde"); @@ -55,7 +54,7 @@ public class SystemInfo { public static final boolean isMacSystemMenu = isMac && "true".equals(System.getProperty("apple.laf.useScreenMenuBar")); - public static final boolean isFileSystemCaseSensitive = !isWindows && !isOS2 && !isMac; + public static final boolean isFileSystemCaseSensitive = SystemInfoRt.isFileSystemCaseSensitive; public static final boolean areSymLinksSupported = isUnix || isWindows && OS_VERSION.compareTo("6.0") >= 0 && isJavaVersionAtLeast("1.7"); diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index a8ab9439d248..c21488878104 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.openapi.util.io; import com.intellij.CommonBundle; @@ -43,27 +42,32 @@ import java.util.*; import java.util.regex.Pattern; @SuppressWarnings({"UtilityClassWithoutPrivateConstructor"}) -public class FileUtil extends FileUtilLight { +public class FileUtil extends FileUtilRt { public static final int MEGABYTE = 1024 * 1024; + @NonNls public static final String ASYNC_DELETE_EXTENSION = ".__del__"; + public static final TObjectHashingStrategy PATH_HASHING_STRATEGY; + static { + if (SystemInfo.isFileSystemCaseSensitive) { + @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) + final TObjectHashingStrategy canonical = TObjectHashingStrategy.CANONICAL; + PATH_HASHING_STRATEGY = canonical; + } + else { + PATH_HASHING_STRATEGY = CaseInsensitiveStringHashingStrategy.INSTANCE; + } + } + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.io.FileUtil"); - private static final ThreadLocal BUFFER = new ThreadLocal() { - protected byte[] initialValue() { - return new byte[1024 * 20]; - } - }; - // do not use channels to copy files larger than 5 Mb because of possible MapFailed error private static final long CHANNELS_COPYING_LIMIT = 5L * MEGABYTE; - private static final int MAX_FILE_DELETE_ATTEMPTS = 10; - public static final Method JAVA_IO_FILESYSTEM_GET_BOOLEAN_ATTRIBUTES_METHOD; - public static final Object/* java.io.FileSystem */ JAVA_IO_FILESYSTEM; - public static final TObjectHashingStrategy T_HASHING_STRATEGY = SystemInfo.isFileSystemCaseSensitive - ? TObjectHashingStrategy.CANONICAL - : CaseInsensitiveStringHashingStrategy.INSTANCE; + private static final int MAX_FILE_DELETE_ATTEMPTS = 10; + + private static final Method JAVA_IO_FILESYSTEM_GET_BOOLEAN_ATTRIBUTES_METHOD; + private static final Object JAVA_IO_FILESYSTEM; // java.io.FileSystem @Nullable public static String getRelativePath(File base, File file) { @@ -206,31 +210,6 @@ public class FileUtil extends FileUtilLight { return bytes; } - @NotNull - public static byte[] loadBytes(@NotNull InputStream stream, int length) throws IOException { - byte[] bytes = new byte[length]; - int count = 0; - while (count < length) { - int n = stream.read(bytes, count, length - count); - if (n <= 0) break; - count += n; - } - return bytes; - } - - @NotNull - public static byte[] loadBytes(@NotNull InputStream stream) throws IOException { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - final byte[] bytes = BUFFER.get(); - while (true) { - int n = stream.read(bytes, 0, bytes.length); - if (n <= 0) break; - buffer.write(bytes, 0, n); - } - buffer.close(); - return buffer.toByteArray(); - } - public static boolean processFirstBytes(@NotNull InputStream stream, int length, @NotNull Processor processor) throws IOException { final byte[] bytes = BUFFER.get(); assert bytes.length >= length : "Cannot process more than " + bytes.length + " in one call, requested:" + length; diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index d4c5412e294e..c687682275dd 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -37,10 +37,12 @@ import java.util.regex.Pattern; //TeamCity inherits StringUtil: do not add private constructors!!! @SuppressWarnings({"UtilityClassWithoutPrivateConstructor"}) -public class StringUtil { +public class StringUtil extends StringUtilRt { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.text.StringUtil"); + @NonNls private static final String VOWELS = "aeiouy"; - private static final Pattern EOL_SPLIT_PATTERN = Pattern.compile(" *(\r|\n|\r\n)+ *"); + @NonNls private static final Pattern EOL_SPLIT_PATTERN = Pattern.compile(" *(\r|\n|\r\n)+ *"); + public static final NotNullFunction QUOTER = new NotNullFunction() { @NotNull public String fun(String s) { @@ -152,16 +154,6 @@ public class StringUtil { return newText!= null ? newText.toString():""; } - @NotNull - public static String getShortName(@NotNull String fqName) { - return getShortName(fqName, '.'); - } - - @NotNull - public static String getShortName(@NotNull Class aClass) { - return getShortName(aClass.getName()); - } - /** * Implementation copied from {@link String#indexOf(String, int)} except character comparisons made case insensitive */ @@ -222,32 +214,6 @@ public class StringUtil { return stringLength >= prefixLength && str.regionMatches(true, 0, prefix, 0, prefixLength); } - public static boolean charsEqualIgnoreCase(char a, char b) { - return a == b || toUpperCase(a) == toUpperCase(b) || toLowerCase(a) == toLowerCase(b); - } - - public static char toUpperCase(char a) { - if (a < 'a') { - return a; - } - if (a >= 'a' && a <= 'z') { - return (char)(a + ('A' - 'a')); - } - return Character.toUpperCase(a); - } - - public static char toLowerCase(final char a) { - if (a < 'A' || a >= 'a' && a <= 'z') { - return a; - } - - if (a >= 'A' && a <= 'Z') { - return (char)(a + ('a' - 'A')); - } - - return Character.toLowerCase(a); - } - public static String stripHtml(String html, boolean convertBreaks) { if (convertBreaks) { html = html.replaceAll("
", "\n\n"); @@ -261,15 +227,6 @@ public class StringUtil { return str == null ? null : str.toLowerCase(); } - @NotNull - public static String getShortName(@NotNull String fqName, char separator) { - int lastPointIdx = fqName.lastIndexOf(separator); - if (lastPointIdx >= 0) { - return fqName.substring(lastPointIdx + 1); - } - return fqName; - } - @NotNull public static String getPackageName(@NotNull String fqName) { return getPackageName(fqName, '.'); @@ -284,101 +241,6 @@ public class StringUtil { return ""; } - /** - * Converts line separators to "\n" - */ - @NotNull - public static String convertLineSeparators(@NotNull String text) { - return convertLineSeparators(text, false); - } - - @NotNull - public static String convertLineSeparators(@NotNull String text, boolean keepCarriageReturn) { - return convertLineSeparators(text, "\n", null, keepCarriageReturn); - } - - @NotNull - public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator) { - return convertLineSeparators(text, newSeparator, null); - } - - @NotNull - public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator, @Nullable int[] offsetsToKeep) { - return convertLineSeparators(text, newSeparator, offsetsToKeep, false); - } - - @NotNull - public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator, @Nullable int[] offsetsToKeep, - boolean keepCarriageReturn) { - StringBuilder buffer = null; - int intactLength = 0; - final boolean newSeparatorIsSlashN = "\n".equals(newSeparator); - for (int i = 0; i < text.length(); i++) { - char c = text.charAt(i); - if (c == '\n') { - if (!newSeparatorIsSlashN) { - if (buffer == null) { - buffer = new StringBuilder(text.length()); - buffer.append(text, 0, intactLength); - } - buffer.append(newSeparator); - shiftOffsets(offsetsToKeep, buffer.length(), 1, newSeparator.length()); - } - else if (buffer == null) { - intactLength++; - } - else { - buffer.append(c); - } - } - else if (c == '\r') { - boolean followedByLineFeed = i < text.length() - 1 && text.charAt(i + 1) == '\n'; - if (!followedByLineFeed && keepCarriageReturn) { - if (buffer == null) { - intactLength++; - } - else { - buffer.append(c); - } - continue; - } - if (buffer == null) { - buffer = new StringBuilder(text.length()); - buffer.append(text, 0, intactLength); - } - buffer.append(newSeparator); - if (followedByLineFeed) { - i++; - shiftOffsets(offsetsToKeep, buffer.length(), 2, newSeparator.length()); - } - else { - shiftOffsets(offsetsToKeep, buffer.length(), 1, newSeparator.length()); - } - } - else { - if (buffer == null) { - intactLength++; - } - else { - buffer.append(c); - } - } - } - return buffer == null ? text : buffer.toString(); - } - - private static void shiftOffsets(int[] offsets, int changeOffset, int oldLength, int newLength) { - if (offsets == null) return; - int shift = newLength - oldLength; - if (shift == 0) return; - for (int i = 0; i < offsets.length; i++) { - int offset = offsets[i]; - if (offset >= changeOffset + oldLength) { - offsets[i] += shift; - } - } - } - public static int getLineBreakCount(@NotNull CharSequence text) { int count = 0; for (int i = 0; i < text.length(); i++) { @@ -2012,24 +1874,6 @@ public class StringUtil { } } - public static int parseInt(final String string, final int defaultValue) { - try { - return Integer.parseInt(string); - } - catch (Exception e) { - return defaultValue; - } - } - - public static double parseDouble(final String string, final double defaultValue) { - try { - return Double.parseDouble(string); - } - catch (Exception e) { - return defaultValue; - } - } - public static int getOccurenceCount(@NotNull String text, final char c) { int res = 0; int i = 0; diff --git a/platform/util/src/com/intellij/util/ArrayUtil.java b/platform/util/src/com/intellij/util/ArrayUtil.java index 009c01f9ba77..a4f92f60f5a8 100644 --- a/platform/util/src/com/intellij/util/ArrayUtil.java +++ b/platform/util/src/com/intellij/util/ArrayUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ package com.intellij.util; import com.intellij.openapi.util.Comparing; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.CharArrayCharSequence; import gnu.trove.Equality; import org.jetbrains.annotations.NotNull; @@ -31,20 +30,20 @@ import java.util.List; /** * Author: msk */ -public class ArrayUtil { - public static final short[] EMPTY_SHORT_ARRAY = new short[0]; - public static final char[] EMPTY_CHAR_ARRAY = new char[0]; - public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - public static final int[] EMPTY_INT_ARRAY = new int[0]; - public static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0]; - @SuppressWarnings({"SSBasedInspection"}) public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; - @SuppressWarnings({"SSBasedInspection"}) public static final String[] EMPTY_STRING_ARRAY = new String[0]; - @SuppressWarnings({"SSBasedInspection"}) public static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; - public static final long[] EMPTY_LONG_ARRAY = new long[0]; - public static final Collection[] EMPTY_COLLECTION_ARRAY = new Collection[0]; +public class ArrayUtil extends ArrayUtilRt { + public static final short[] EMPTY_SHORT_ARRAY = ArrayUtilRt.EMPTY_SHORT_ARRAY; + public static final char[] EMPTY_CHAR_ARRAY = ArrayUtilRt.EMPTY_CHAR_ARRAY; + public static final byte[] EMPTY_BYTE_ARRAY = ArrayUtilRt.EMPTY_BYTE_ARRAY; + public static final int[] EMPTY_INT_ARRAY = ArrayUtilRt.EMPTY_INT_ARRAY; + public static final boolean[] EMPTY_BOOLEAN_ARRAY = ArrayUtilRt.EMPTY_BOOLEAN_ARRAY; + public static final Object[] EMPTY_OBJECT_ARRAY = ArrayUtilRt.EMPTY_OBJECT_ARRAY; + public static final String[] EMPTY_STRING_ARRAY = ArrayUtilRt.EMPTY_STRING_ARRAY; + public static final Class[] EMPTY_CLASS_ARRAY = ArrayUtilRt.EMPTY_CLASS_ARRAY; + public static final long[] EMPTY_LONG_ARRAY = ArrayUtilRt.EMPTY_LONG_ARRAY; + public static final Collection[] EMPTY_COLLECTION_ARRAY = ArrayUtilRt.EMPTY_COLLECTION_ARRAY; + public static final File[] EMPTY_FILE_ARRAY = ArrayUtilRt.EMPTY_FILE_ARRAY; + public static final Runnable[] EMPTY_RUNNABLE_ARRAY = ArrayUtilRt.EMPTY_RUNNABLE_ARRAY; public static final CharSequence EMPTY_CHAR_SEQUENCE = new CharArrayCharSequence(EMPTY_CHAR_ARRAY); - public static final File[] EMPTY_FILE_ARRAY = new File[0]; - public static final Runnable[] EMPTY_RUNNABLE_ARRAY = new Runnable[0]; public static final ArrayFactory STRING_ARRAY_FACTORY = new ArrayFactory() { @Override @@ -125,13 +124,13 @@ public class ArrayUtil { @NotNull public static T[] toObjectArray(@NotNull Collection collection, @NotNull Class aClass) { - T[] array = (T[])Array.newInstance(aClass, collection.size()); + @SuppressWarnings("unchecked") T[] array = (T[])Array.newInstance(aClass, collection.size()); return collection.toArray(array); } @NotNull public static T[] toObjectArray(@NotNull Class aClass, Object... source) { - T[] array = (T[])Array.newInstance(aClass, source.length); + @SuppressWarnings("unchecked") T[] array = (T[])Array.newInstance(aClass, source.length); System.arraycopy(source, 0, array, 0, array.length); return array; } @@ -143,12 +142,6 @@ public class ArrayUtil { return collection.toArray(new Object[collection.size()]); } - @NotNull - public static String[] toStringArray(@NotNull Collection collection) { - if (collection.isEmpty()) return EMPTY_STRING_ARRAY; - return ContainerUtil.toArray(collection, new String[collection.size()]); - } - @NotNull public static int[] toIntArray(@NotNull List list) { int[] ret = new int[list.size()]; diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 2e85f0996935..5f3b4e7f39c0 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -29,10 +29,9 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Array; import java.util.*; -import java.util.concurrent.CopyOnWriteArrayList; @SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "unchecked"}) -public class ContainerUtil { +public class ContainerUtil extends ContainerUtilRt { private static final int INSERTION_SORT_THRESHOLD = 10; public static Map intersection(Map map1, Map map2) { @@ -290,34 +289,6 @@ public class ContainerUtil { return null; } - @NotNull - public static List map2List(@NotNull T[] array, @NotNull Function mapper) { - return map2List(Arrays.asList(array), mapper); - } - - @NotNull - public static List map2List(@NotNull Collection collection, @NotNull Function mapper) { - final ArrayList list = new ArrayList(collection.size()); - for (final T t : collection) { - list.add(mapper.fun(t)); - } - return list; - } - - @NotNull - public static Set map2Set(@NotNull T[] collection, @NotNull Function mapper) { - return map2Set(Arrays.asList(collection), mapper); - } - - @NotNull - public static Set map2Set(@NotNull Collection collection, @NotNull Function mapper) { - final HashSet set = new HashSet(collection.size()); - for (final T t : collection) { - set.add(mapper.fun(t)); - } - return set; - } - @NotNull public static Map map2Map(@NotNull T[] collection, @NotNull Function> mapper) { return map2Map(Arrays.asList(collection), mapper); @@ -736,38 +707,6 @@ public class ContainerUtil { public static T[] mergeCollectionsToArray(@NotNull Collection c1, @NotNull Collection c2, @NotNull ArrayFactory factory) { return ArrayUtil.mergeCollections(c1, c2, factory); } - - @NotNull - public static T[] toArray(@NotNull List collection, @NotNull T[] array) { - final int length = array.length; - if (length < 20) { - for (int i = 0; i < collection.size(); i++) { - array[i] = collection.get(i); - } - return array; - } - else { - return collection.toArray(array); - } - } - - /** - * This is a replacement for {@link Collection#toArray(Object[])}. For small collections it is faster to stay at java level and refrain - * from calling JNI {@link System#arraycopy(Object, int, Object, int, int)} - */ - @NotNull - public static T[] toArray(@NotNull Collection c, @NotNull T[] sample) { - final int size = c.size(); - if (size == sample.length && size < 20) { - int i = 0; - for (T t : c) { - sample[i++] = t; - } - return sample; - } - - return c.toArray(sample); - } public static > void sort(@NotNull List list) { int size = list.size(); @@ -980,17 +919,6 @@ public class ContainerUtil { return addAll(new HashSet(), items); } - public static void addIfNotNull(final T element, @NotNull Collection result) { - if (element != null) { - result.add(element); - } - } - public static void addIfNotNull(@NotNull Collection result, @Nullable final T element) { - if (element != null) { - result.add(element); - } - } - public static void putIfNotNull(final K key, @Nullable V value, @NotNull final Map result) { if (value != null) { result.put(key, value); @@ -1166,17 +1094,6 @@ public class ContainerUtil { } } - @NotNull - public static CopyOnWriteArrayList createEmptyCOWList() { - // does not create garbage new Object[0] - return new CopyOnWriteArrayList(ContainerUtil.emptyList()); - } - - @NotNull - public static List emptyList() { - return (List)EmptyList.INSTANCE; - } - /** * Merge sorted points, which are sorted by x and with equal x by y. * Result is put to x1 y1. @@ -1228,35 +1145,6 @@ public class ContainerUtil { y1.add(newY.toNativeArray()); } - /** - * has optimized toArray() as opposed to the {@link java.util.Collections#emptyList()} - */ - private static class EmptyList extends AbstractList implements RandomAccess { - private static final EmptyList INSTANCE = new EmptyList(); - - public int size() { - return 0; - } - - public boolean contains(Object obj) { - return false; - } - - public Object get(int index) { - throw new IndexOutOfBoundsException("Index: " + index); - } - - @Override - public Object[] toArray() { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - - @Override - public T[] toArray(T[] a) { - return a; - } - } - @NotNull public static Set singleton(final T o, @NotNull final TObjectHashingStrategy strategy) { return new Set() { diff --git a/platform/util/src/com/intellij/util/ui/FormBuilder.java b/platform/util/src/com/intellij/util/ui/FormBuilder.java index f5437de681c5..e7065dfd71a7 100644 --- a/platform/util/src/com/intellij/util/ui/FormBuilder.java +++ b/platform/util/src/com/intellij/util/ui/FormBuilder.java @@ -52,15 +52,15 @@ public class FormBuilder { return new FormBuilder(); } - public FormBuilder addLabeledComponent(@Nullable JLabel label, JComponent component) { + public FormBuilder addLabeledComponent(@Nullable JComponent label, JComponent component) { return addLabeledComponent(label, component, myVerticalGap, false); } - public FormBuilder addLabeledComponent(@Nullable JLabel label, JComponent component, final int topInset) { + public FormBuilder addLabeledComponent(@Nullable JComponent label, JComponent component, final int topInset) { return addLabeledComponent(label, component, topInset, false); } - public FormBuilder addLabeledComponent(@Nullable JLabel label, JComponent component, boolean labelOnTop) { + public FormBuilder addLabeledComponent(@Nullable JComponent label, JComponent component, boolean labelOnTop) { return addLabeledComponent(label, component, myVerticalGap, labelOnTop); } diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index b4740ec6c465..002432d18d20 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.util.ui; +import com.intellij.BundleBase; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.*; @@ -100,7 +101,7 @@ public class UIUtil { public enum ComponentStyle {REGULAR, SMALL, MINI} public enum FontColor {NORMAL, BRIGHTER} - public static final char MNEMONIC = 0x1B; + public static final char MNEMONIC = BundleBase.MNEMONIC; @NonNls public static final String HTML_MIME = "text/html"; @NonNls public static final String JSLIDER_ISFILLED = "JSlider.isFilled"; @NonNls public static final String ARIAL_FONT_NAME = "Arial"; @@ -384,43 +385,7 @@ public class UIUtil { } public static String replaceMnemonicAmpersand(final String value) { - if (value.indexOf('&') >= 0) { - boolean useMacMnemonic = value.contains("&&"); - StringBuilder realValue = new StringBuilder(); - int i = 0; - while (i < value.length()) { - char c = value.charAt(i); - if (c == '\\') { - if (i < value.length() - 1 && value.charAt(i + 1) == '&') { - realValue.append('&'); - i++; - } - else { - realValue.append(c); - } - } - else if (c == '&') { - if (i < value.length() - 1 && value.charAt(i + 1) == '&') { - if (SystemInfo.isMac) { - realValue.append(MNEMONIC); - } - i++; - } - else { - if (!SystemInfo.isMac || !useMacMnemonic) { - realValue.append(MNEMONIC); - } - } - } - else { - realValue.append(c); - } - i++; - } - - return realValue.toString(); - } - return value; + return BundleBase.replaceMnemonicAmpersand(value); } public static Color getTableHeaderBackground() { diff --git a/platform/util/util.iml b/platform/util/util.iml index 160382d542e7..378b380da974 100644 --- a/platform/util/util.iml +++ b/platform/util/util.iml @@ -15,6 +15,7 @@ + diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRoot.java b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRoot.java index d43190347b75..c05995636b45 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRoot.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsRoot.java @@ -52,4 +52,12 @@ public class VcsRoot { } return hashcode; } + + @Override + public String toString() { + return "VcsRoot{" + + "vcs=" + vcs + + ", path=" + path + + '}'; + } } \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/AbstractRefreshablePanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/AbstractRefreshablePanel.java index af635d50dbe2..32a8085acedd 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/AbstractRefreshablePanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/AbstractRefreshablePanel.java @@ -135,7 +135,9 @@ public abstract class AbstractRefreshablePanel implements RefreshablePanel { cause = e; } LOG.info(e); - VcsBalloonProblemNotifier.showOverChangesView(myProject, cause.getMessage() == null ? e.getMessage() : cause.getMessage(), MessageType.ERROR); + String message = cause.getMessage() == null ? e.getMessage() : cause.getMessage(); + message = message == null ? "Unknown error" : message; + VcsBalloonProblemNotifier.showOverChangesView(myProject, message, MessageType.ERROR); } @Override diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java index 61b1c353590f..b5e0e447a739 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java @@ -65,4 +65,12 @@ public class FilePathUnderVcs { } return hashcode; } + + @Override + public String toString() { + return "FilePathUnderVcs{" + + "myPath=" + myPath + + ", myVcs=" + myVcs + + '}'; + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java index c850c88d6820..c06b21fb42bd 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java @@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.changes.committed; import com.intellij.concurrency.JobScheduler; import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.PersistentStateComponent; @@ -743,8 +744,24 @@ public class CommittedChangesCache implements PersistentStateComponent receivedChanges) { final Collection changes = receivedChanges == null ? myCachedIncomingChangeLists : receivedChanges; if (changes == null) { - final List lists = loadIncomingChanges(false); - myBus.syncPublisher(COMMITTED_TOPIC).incomingChangesUpdated(new ArrayList(lists)); + final Application application = ApplicationManager.getApplication(); + final Runnable runnable = new Runnable() { + @Override + public void run() { + final List lists = loadIncomingChanges(false); + application.invokeLater(new Runnable() { + @Override + public void run() { + myBus.syncPublisher(COMMITTED_TOPIC).incomingChangesUpdated(new ArrayList(lists)); + } + }); + } + }; + if (application.isDispatchThread()) { + application.executeOnPooledThread(runnable); + } else { + runnable.run(); + } return; } final ArrayList listCopy = new ArrayList(changes); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java index 1f9bba3fa3b1..008a1ad75491 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java @@ -676,7 +676,7 @@ public class FileHistoryPanelImpl extends PanelWithActionsAndCloseButton { final JLabel commentLabel = new JLabel(COMMIT_MESSAGE_TITLE + ":") { @Override public Dimension getPreferredSize() { - return new Dimension(super.getWidth(), 29); + return super.getPreferredSize(); } }; commentGroup.add(commentLabel, BorderLayout.NORTH); diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java index 2221502b153f..9e8ad8fc9e2d 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java @@ -16,9 +16,11 @@ package com.intellij.android.designer.model; import com.android.ide.common.rendering.api.ViewInfo; +import com.android.resources.ResourceType; import com.android.sdklib.IAndroidTarget; import com.intellij.android.designer.propertyTable.AttributeProperty; import com.intellij.android.designer.propertyTable.FlagProperty; +import com.intellij.android.designer.propertyTable.editors.ResourceDialog; import com.intellij.designer.model.MetaManager; import com.intellij.designer.model.MetaModel; import com.intellij.designer.model.RadComponent; @@ -33,6 +35,7 @@ import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.sdk.AndroidTargetData; import org.jetbrains.android.uipreview.ProjectClassLoader; import org.jetbrains.android.uipreview.RenderServiceFactory; +import org.jetbrains.annotations.NotNull; import java.util.*; @@ -43,12 +46,14 @@ import java.util.*; public class PropertyParser { public static final String KEY = "PROPERTY_PARSER"; + private final Module myModule; private MetaManager myMetaManager; private AttributeDefinitions myDefinitions; private ProjectClassLoader myClassLoader; private Map> myCachedProperties; public PropertyParser(Module module, IAndroidTarget target) throws Exception { + myModule = module; myMetaManager = ViewsMetaManager.getInstance(module.getProject()); myCachedProperties = myMetaManager.getCache(target.hashString()); if (myCachedProperties == null) { @@ -166,4 +171,9 @@ public class PropertyParser { return properties; } + + @NotNull + public ResourceDialog createResourceDialog(ResourceType... types) { + return new ResourceDialog(myModule, types); + } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java index 8fbcc73a3caf..356fda1dfcc9 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java @@ -15,8 +15,11 @@ */ package com.intellij.android.designer.propertyTable; +import com.android.resources.ResourceType; +import com.intellij.android.designer.model.PropertyParser; import com.intellij.android.designer.model.RadViewComponent; import com.intellij.android.designer.propertyTable.editors.BooleanEditor; +import com.intellij.android.designer.propertyTable.editors.ResourceDialog; import com.intellij.android.designer.propertyTable.editors.StringsComboEditor; import com.intellij.android.designer.propertyTable.renderers.BooleanRenderer; import com.intellij.designer.model.RadComponent; @@ -26,6 +29,7 @@ import com.intellij.designer.propertyTable.PropertyRenderer; import com.intellij.designer.propertyTable.editors.AbstractTextFieldEditor; import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.xml.XmlAttribute; @@ -141,12 +145,22 @@ public class AttributeProperty extends Property { private static class TextDialogEditor extends PropertyEditor { private TextFieldWithBrowseButton myTextField; + private RadComponent myRootComponent; public TextDialogEditor() { myTextField = new TextFieldWithBrowseButton(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - // TODO: Auto-generated method stub + PropertyParser parser = myRootComponent.getClientProperty(PropertyParser.KEY); + ResourceDialog dialog = parser + .createResourceDialog(ResourceType.BOOL, ResourceType.COLOR, ResourceType.DIMEN, ResourceType.DRAWABLE, ResourceType.INTEGER, + ResourceType.STRING, ResourceType.ID); + dialog.show(); + + if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + myTextField.setText(dialog.getResourceName()); + fireValueCommitted(true, false); + } } }); myTextField.getTextField().setBorder(null); @@ -154,7 +168,8 @@ public class AttributeProperty extends Property { @NotNull @Override - public JComponent getComponent(@Nullable RadComponent component, Object value) { + public JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value) { + myRootComponent = rootComponent; myTextField.setText(value == null ? "" : value.toString()); myTextField.getTextField().setBorder(null); return myTextField; diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java new file mode 100644 index 000000000000..03f2b7c91d20 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java @@ -0,0 +1,308 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.propertyTable.editors; + +import com.android.resources.ResourceType; +import com.intellij.designer.componentTree.TreeNodeDescriptor; +import com.intellij.ide.util.treeView.AbstractTreeBuilder; +import com.intellij.ide.util.treeView.AbstractTreeStructure; +import com.intellij.ide.util.treeView.NodeDescriptor; +import com.intellij.ide.util.treeView.NodeRenderer; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.Disposer; +import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.ui.TreeSpeedSearch; +import com.intellij.ui.components.JBTabbedPane; +import com.intellij.ui.speedSearch.SpeedSearchUtil; +import com.intellij.ui.treeStructure.Tree; +import com.intellij.util.ArrayUtil; +import com.intellij.util.ui.tree.TreeUtil; +import org.jetbrains.android.facet.AndroidFacet; +import org.jetbrains.android.resourceManagers.ResourceManager; +import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeSelectionModel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.*; +import java.util.List; + +/** + * @author Alexander Lobas + */ +public class ResourceDialog extends DialogWrapper implements TreeSelectionListener { + private final JBTabbedPane myContentPanel; + private final ResourcePanel myProjectPanel; + private final ResourcePanel mySystemPanel; + private final Action myNewResourceAction = new AbstractAction("New Resource...") { + @Override + public void actionPerformed(ActionEvent e) { + // TODO: Auto-generated method stub + } + }; + private String myResultResourceName; + + public ResourceDialog(Module module, ResourceType[] types) { + super(module.getProject()); + + setTitle("Resource Dialog"); + getOKAction().setEnabled(false); + + AndroidFacet facet = AndroidFacet.getInstance(module); + myProjectPanel = new ResourcePanel(facet, types, false); + mySystemPanel = new ResourcePanel(facet, types, true); + + myContentPanel = new JBTabbedPane(); + myContentPanel.setPreferredSize(new Dimension(500, 400)); + myContentPanel.addTab("Project", myProjectPanel.myComponent); + myContentPanel.addTab("System", mySystemPanel.myComponent); + + myContentPanel.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + myNewResourceAction.setEnabled(myContentPanel.getSelectedComponent() == myProjectPanel.myComponent); + valueChanged(null); + } + }); + + init(); + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myProjectPanel.myTree; + } + + @Override + protected JComponent createCenterPanel() { + return myContentPanel; + } + + @Override + protected Action[] createLeftSideActions() { + return new Action[]{myNewResourceAction}; + } + + @Override + protected void dispose() { + super.dispose(); + Disposer.dispose(myProjectPanel.myTreeBuilder); + Disposer.dispose(mySystemPanel.myTreeBuilder); + } + + public String getResourceName() { + return myResultResourceName; + } + + @Override + public void valueChanged(TreeSelectionEvent e) { + ResourcePanel panel = myContentPanel.getSelectedComponent() == myProjectPanel.myComponent ? myProjectPanel : mySystemPanel; + Set elements = panel.myTreeBuilder.getSelectedElements(ResourceItem.class); + getOKAction().setEnabled(!elements.isEmpty()); + + if (elements.isEmpty()) { + myResultResourceName = null; + } + else { + String prefix = panel == myProjectPanel ? "@" : "@android:"; + myResultResourceName = prefix + elements.iterator().next().getName(); + } + } + + private class ResourcePanel { + public final Tree myTree; + public final AbstractTreeBuilder myTreeBuilder; + public final JScrollPane myComponent; + + public ResourcePanel(AndroidFacet facet, ResourceType[] types, boolean system) { + myTree = new Tree(); + myTree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode())); + myTree.setScrollsOnExpand(true); + myTree.setRootVisible(false); + myTree.setShowsRootHandles(true); + ToolTipManager.sharedInstance().registerComponent(myTree); + TreeUtil.installActions(myTree); + + ResourceManager manager = facet.getResourceManager(system ? AndroidUtils.SYSTEM_RESOURCE_PACKAGE : null); + ResourceGroup[] groups = new ResourceGroup[types.length]; + + for (int i = 0; i < types.length; i++) { + groups[i] = new ResourceGroup(types[i], manager); + } + + myTreeBuilder = + new AbstractTreeBuilder(myTree, (DefaultTreeModel)myTree.getModel(), new TreeContentProvider(groups), null); + myTreeBuilder.initRootNode(); + + TreeSelectionModel selectionModel = myTree.getSelectionModel(); + selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + selectionModel.addTreeSelectionListener(ResourceDialog.this); + + myTree.setCellRenderer(new NodeRenderer() { + @Override + protected void doAppend(@NotNull @Nls String fragment, + @NotNull SimpleTextAttributes attributes, + boolean isMainText, + boolean selected) { + SpeedSearchUtil.appendFragmentsForSpeedSearch(myTree, fragment, attributes, selected, this); + } + + @Override + public void doAppend(@NotNull String fragment, @NotNull SimpleTextAttributes attributes, boolean selected) { + SpeedSearchUtil.appendFragmentsForSpeedSearch(myTree, fragment, attributes, selected, this); + } + + @Override + public void doAppend(String fragment, boolean selected) { + SpeedSearchUtil.appendFragmentsForSpeedSearch(myTree, fragment, SimpleTextAttributes.REGULAR_ATTRIBUTES, selected, this); + } + }); + new TreeSpeedSearch(myTree, TreeSpeedSearch.NODE_DESCRIPTOR_TOSTRING, true); + + myComponent = ScrollPaneFactory.createScrollPane(myTree); + } + } + + private static class ResourceGroup { + private List myItems = new ArrayList(); + private final ResourceType myType; + + public ResourceGroup(ResourceType type, ResourceManager manager) { + myType = type; + + Collection resourceNames = manager.getValueResourceNames(type.getName()); + for (String resourceName : resourceNames) { + myItems.add(new ResourceItem(this, resourceName)); + } + + for (String file : manager.getFileResourcesNames(type.getName())) { + myItems.add(new ResourceItem(this, file)); + } + + if (type == ResourceType.ID) { + for (String id : manager.getIds()) { + if (!resourceNames.contains(id)) { + myItems.add(new ResourceItem(this, id)); + } + } + } + + Collections.sort(myItems, new Comparator() { + @Override + public int compare(ResourceItem resource1, ResourceItem resource2) { + return resource1.toString().compareTo(resource2.toString()); + } + }); + } + + public String getName() { + return myType.getName(); + } + + public List getItems() { + return myItems; + } + + @Override + public String toString() { + return myType.getDisplayName(); + } + } + + private static class ResourceItem { + private final ResourceGroup myGroup; + private final String myName; + + public ResourceItem(@NotNull ResourceGroup group, @NotNull String name) { + myGroup = group; + myName = name; + } + + public ResourceGroup getGroup() { + return myGroup; + } + + public String getName() { + return myGroup.getName() + "/" + myName; + } + + @Override + public String toString() { + return myName; + } + } + + private static class TreeContentProvider extends AbstractTreeStructure { + private final Object myTreeRoot = new Object(); + private final ResourceGroup[] myGroups; + + public TreeContentProvider(ResourceGroup[] groups) { + myGroups = groups; + } + + @Override + public Object getRootElement() { + return myTreeRoot; + } + + @Override + public Object[] getChildElements(Object element) { + if (element == myTreeRoot) { + return myGroups; + } + if (element instanceof ResourceGroup) { + ResourceGroup group = (ResourceGroup)element; + return group.getItems().toArray(); + } + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } + + @Override + public Object getParentElement(Object element) { + if (element instanceof ResourceItem) { + ResourceItem resource = (ResourceItem)element; + return resource.getGroup(); + } + return null; + } + + @NotNull + @Override + public NodeDescriptor createDescriptor(Object element, NodeDescriptor parentDescriptor) { + return new TreeNodeDescriptor(parentDescriptor, element, element == null ? null : element.toString()); + } + + @Override + public boolean hasSomethingToCommit() { + return false; + } + + @Override + public void commit() { + } + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/StringsComboEditor.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/StringsComboEditor.java index ea286687ea59..8028c3f5e0d4 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/StringsComboEditor.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/StringsComboEditor.java @@ -32,7 +32,7 @@ public class StringsComboEditor extends ComboEditor { @NotNull @Override - public JComponent getComponent(@Nullable RadComponent component, Object value) { + public JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value) { myCombo.setSelectedItem(value); return myCombo; } diff --git a/plugins/android/resources/messages/AndroidBundle.properties b/plugins/android/resources/messages/AndroidBundle.properties index ba66305c6f68..a5203a77da24 100644 --- a/plugins/android/resources/messages/AndroidBundle.properties +++ b/plugins/android/resources/messages/AndroidBundle.properties @@ -36,7 +36,8 @@ activity.class.not.specified.error=Activity class not specified not.activity.subclass.error={0} is not an Activity subclass no.facet.error=No Android facet found for {0} android.logcat.tab.title=Logcat -android.logcat.title=Android Logcat +android.adb.logs.tab.title=ADB logs +android.logcat.title=Android android.logcat.error.dialog.title=Android Logcat Error android.logcat.color.page.name=Android Logcat warning.level.title=Warning diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml index 1cfc42b1a4fd..008774bdaad1 100644 --- a/plugins/android/src/META-INF/plugin.xml +++ b/plugins/android/src/META-INF/plugin.xml @@ -181,7 +181,7 @@ - { return ApplicationManager.getApplication().runReadAction(new Computable() { @Nullable public PsiClass compute() { - return c.getSuperClass(); + return c.isValid() ? c.getSuperClass() : null; } }); } diff --git a/plugins/android/src/org/jetbrains/android/dom/manifest/ManifestDomFileDescription.java b/plugins/android/src/org/jetbrains/android/dom/manifest/ManifestDomFileDescription.java index acea0d6bb5f5..641838ee575c 100644 --- a/plugins/android/src/org/jetbrains/android/dom/manifest/ManifestDomFileDescription.java +++ b/plugins/android/src/org/jetbrains/android/dom/manifest/ManifestDomFileDescription.java @@ -42,7 +42,7 @@ public class ManifestDomFileDescription extends DomFileDescription { return false; } final Module module = ModuleUtil.findModuleForPsiElement(file); - return module == null || AndroidFacet.getInstance(module) != null; + return module == null || !module.isDisposed() && AndroidFacet.getInstance(module) != null; } protected void initializeFileDescription() { diff --git a/plugins/android/src/org/jetbrains/android/logcat/AdbErrors.java b/plugins/android/src/org/jetbrains/android/logcat/AdbErrors.java new file mode 100644 index 000000000000..4fd6125e134d --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/logcat/AdbErrors.java @@ -0,0 +1,37 @@ +package org.jetbrains.android.logcat; + +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +public class AdbErrors { + private AdbErrors() { + } + + private static volatile List ourAdbErrorList; + + @NotNull + public static synchronized String[] getErrors() { + return ourAdbErrorList != null ? ArrayUtil.toStringArray(ourAdbErrorList) : ArrayUtil.EMPTY_STRING_ARRAY; + } + + public static synchronized void clear() { + if (ourAdbErrorList != null) { + ourAdbErrorList.clear(); + } + } + + public static synchronized void reportError(@NotNull String message, @Nullable String tag) { + final String fullMessage = tag != null ? tag + ": " + message : message; + if (ourAdbErrorList == null) { + ourAdbErrorList = new ArrayList(); + } + ourAdbErrorList.add(fullMessage); + } +} diff --git a/plugins/android/src/org/jetbrains/android/logcat/AndroidLogcatToolWindowFactory.java b/plugins/android/src/org/jetbrains/android/logcat/AndroidLogcatToolWindowFactory.java index 82f5a22cdd84..389f0f05b1a6 100644 --- a/plugins/android/src/org/jetbrains/android/logcat/AndroidLogcatToolWindowFactory.java +++ b/plugins/android/src/org/jetbrains/android/logcat/AndroidLogcatToolWindowFactory.java @@ -16,8 +16,10 @@ package org.jetbrains.android.logcat; +import com.android.ddmlib.Log; import com.intellij.ProjectTopics; import com.intellij.execution.filters.HyperlinkInfo; +import com.intellij.execution.impl.ConsoleViewImpl; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.facet.ProjectFacetManager; @@ -34,6 +36,7 @@ import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter; import com.intellij.openapi.wm.ex.ToolWindowManagerEx; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentManager; +import com.intellij.ui.content.impl.ContentImpl; import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.maven.AndroidMavenUtil; @@ -90,12 +93,34 @@ public class AndroidLogcatToolWindowFactory implements ToolWindowFactory { JPanel contentPanel = view.getContentPanel(); final ContentManager contentManager = toolWindow.getContentManager(); - final Content content = contentManager.getFactory().createContent(contentPanel, null, false); - content.setDisposer(view); - content.setCloseable(false); - content.setPreferredFocusableComponent(contentPanel); - contentManager.addContent(content); - contentManager.setSelectedContent(content, true); + + final Content logcatContent = + contentManager.getFactory().createContent(contentPanel, AndroidBundle.message("android.logcat.tab.title"), false); + logcatContent.setDisposer(view); + logcatContent.setCloseable(false); + logcatContent.setPreferredFocusableComponent(contentPanel); + contentManager.addContent(logcatContent); + contentManager.setSelectedContent(logcatContent, true); + + final ConsoleView console = new ConsoleViewImpl(project, false); + final Content adbLogsContent = new ContentImpl(console.getComponent(), AndroidBundle.message("android.adb.logs.tab.title"), false); + adbLogsContent.setCloseable(false); + contentManager.addContent(adbLogsContent); + + //noinspection UnnecessaryFullyQualifiedName + com.android.ddmlib.Log.setLogOutput(new Log.ILogOutput() { + @Override + public void printLog(Log.LogLevel logLevel, String tag, String message) { + reportAdbLogMessage(logLevel, tag, message, console); + } + + @Override + public void printAndPromptLog(Log.LogLevel logLevel, String tag, String message) { + // todo: should we show dialog? + reportAdbLogMessage(logLevel, tag, message, console); + } + }); + ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { view.activate(); @@ -107,6 +132,48 @@ public class AndroidLogcatToolWindowFactory implements ToolWindowFactory { }); } + private static void reportAdbLogMessage(Log.LogLevel logLevel, String tag, String message, @NotNull ConsoleView consoleView) { + if (message == null) { + return; + } + if (logLevel == null) { + logLevel = Log.LogLevel.INFO; + } + + if (logLevel == Log.LogLevel.ERROR || logLevel == Log.LogLevel.ASSERT) { + AdbErrors.reportError(message, tag); + } + + final ConsoleViewContentType contentType = toConsoleViewContentType(logLevel); + if (contentType == null) { + return; + } + + final String fullMessage = tag != null ? tag + ": " + message : message; + consoleView.print(fullMessage + '\n', contentType); + } + + @Nullable + private static ConsoleViewContentType toConsoleViewContentType(@NotNull Log.LogLevel logLevel) { + switch (logLevel) { + case VERBOSE: + return null; + case DEBUG: + return null; + case INFO: + return ConsoleViewContentType.getConsoleViewType(AndroidLogcatConstants.INFO); + case WARN: + return ConsoleViewContentType.getConsoleViewType(AndroidLogcatConstants.WARNING); + case ERROR: + return ConsoleViewContentType.getConsoleViewType(AndroidLogcatConstants.ERROR); + case ASSERT: + return ConsoleViewContentType.getConsoleViewType(AndroidLogcatConstants.ASSERT); + default: + assert false : "Unknown log level " + logLevel; + } + return null; + } + private static void checkFacetAndSdk(Project project, AndroidLogcatToolWindowView view) { final List facets = ProjectFacetManager.getInstance(project).getFacets(AndroidFacet.ID); final ConsoleView console = view.getLogConsole().getConsole(); diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkData.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkData.java index c63650b914fb..616a78281a17 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkData.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkData.java @@ -18,6 +18,7 @@ package org.jetbrains.android.sdk; import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.DdmPreferences; +import com.android.ddmlib.Log; import com.android.sdklib.*; import com.android.sdklib.internal.project.ProjectProperties; import com.intellij.CommonBundle; @@ -33,6 +34,7 @@ import com.intellij.reference.SoftReference; import com.intellij.util.containers.HashMap; import gnu.trove.TIntObjectHashMap; import org.jetbrains.android.actions.AndroidEnableAdbServiceAction; +import org.jetbrains.android.logcat.AdbErrors; import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.android.util.BufferingFileWrapper; @@ -182,12 +184,15 @@ public class AndroidSdkData { return getLocation().hashCode(); } + @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") private boolean initializeDdmlib(@NotNull Project project) { ApplicationManager.getApplication().assertIsDispatchThread(); while (true) { final MyInitializeDdmlibTask task = new MyInitializeDdmlibTask(project); + AdbErrors.clear(); + Thread t = new Thread(new Runnable() { @Override public void run() { @@ -205,25 +210,33 @@ public class AndroidSdkData { boolean finished = task.isFinished(); - //noinspection AssignmentToStaticFieldFromInstanceMethod - myAdbCrashed = !finished; - if (task.isCanceled()) { + myAdbCrashed = !finished; forceInterrupt(t); return false; } - if (!finished) { - int result = Messages - .showOkCancelDialog(project, - "ADB not responding. Please, kill \"" + SdkConstants.FN_ADB + "\" process manually and click 'Retry'", - CommonBundle.getErrorTitle(), "&Retry", "&Cancel", Messages.getErrorIcon()); + myAdbCrashed = false; - if (result == 1) { + if (!finished) { + final String adbErrorString = combine(AdbErrors.getErrors()); + final int result = Messages.showDialog(project, "ADB not responding. You can wait more, or kill \"" + + SdkConstants.FN_ADB + + "\" process manually and click 'Restart'" + + (adbErrorString.length() > 0 ? "\nErrors from ADB:\n" + adbErrorString : ""), + CommonBundle.getErrorTitle(), new String[]{"&Wait more", "&Restart", "&Cancel"}, 0, + Messages.getErrorIcon()); + if (result == 2) { + // cancel + myAdbCrashed = true; forceInterrupt(t); return false; } - retryWas = true; + else if (result == 1) { + // restart + myAdbCrashed = true; + retryWas = true; + } } } @@ -236,6 +249,19 @@ public class AndroidSdkData { return true; } + @NotNull + private static String combine(@NotNull String[] strs) { + final StringBuilder builder = new StringBuilder(); + + for (String str : strs) { + if (builder.length() > 0) { + builder.append('\n'); + } + builder.append(str); + } + return builder.toString(); + } + @SuppressWarnings({"BusyWait"}) private static void forceInterrupt(Thread thread) { /* @@ -262,6 +288,7 @@ public class AndroidSdkData { synchronized (myDdmsLock) { if (!myDdmLibInitialized) { myDdmLibInitialized = true; + DdmPreferences.setLogLevel(Log.LogLevel.INFO.getStringValue()); DdmPreferences.setTimeOut(AndroidUtils.TIMEOUT); AndroidDebugBridge.init(AndroidEnableAdbServiceAction.isAdbServiceEnabled()); LOG.info("DDMLib initialized"); diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/actions/GenerateCopyrightAction.java b/plugins/copyright/src/com/maddyhome/idea/copyright/actions/GenerateCopyrightAction.java index e5f1a32b138a..9e58609dca9f 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/actions/GenerateCopyrightAction.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/actions/GenerateCopyrightAction.java @@ -73,7 +73,7 @@ public class GenerateCopyrightAction extends AnAction PsiFile file = getFile(context, project); assert file != null; if (CopyrightManager.getInstance(project).getCopyrightOptions(file) == null) { - if (Messages.showOkCancelDialog(project, "No copyright configured for current file. Would you like to edit copyright settings?", "No copyright available", Messages.getQuestionIcon()) == DialogWrapper.OK_EXIT_CODE) { + if (Messages.showOkCancelDialog(project, "No copyright configured for current file. Would you like to edit copyright settings?", "No Copyright Available", Messages.getQuestionIcon()) == DialogWrapper.OK_EXIT_CODE) { ShowSettingsUtil.getInstance().showSettingsDialog(project, new CopyrightProjectConfigurable(project).getDisplayName()); } else { return; diff --git a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringUtils.java b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringUtils.java index e582eb2c336c..c74798537cb2 100644 --- a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringUtils.java +++ b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringUtils.java @@ -18,7 +18,6 @@ package org.jetbrains.generate.tostring; import com.intellij.codeInsight.generation.PsiElementClassMember; import com.intellij.codeInsight.generation.PsiFieldMember; import com.intellij.codeInsight.generation.PsiMethodMember; -import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; @@ -31,7 +30,6 @@ import org.jetbrains.generate.tostring.exception.GenerateCodeException; import org.jetbrains.generate.tostring.exception.PluginException; import org.jetbrains.generate.tostring.psi.PsiAdapter; -import java.io.File; import java.util.ArrayList; import java.util.List; @@ -142,9 +140,8 @@ public class GenerateToStringUtils { * @param e the caused exception. * @throws RuntimeException is thrown for severe exceptions */ - public static void handleExeption(Project project, Exception e) throws RuntimeException { - e.printStackTrace(); // must print stacktrace to see caused in IDEA log / console - log.error(e); + public static void handleException(Project project, Exception e) throws RuntimeException { + log.info(e); if (e instanceof GenerateCodeException) { // code generation error - display velocity errror in error dialog so user can identify problem quicker diff --git a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringWorker.java b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringWorker.java index 0eb91c0fd2a8..d2dd14f394ef 100644 --- a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringWorker.java +++ b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringWorker.java @@ -382,7 +382,7 @@ public class GenerateToStringWorker { new GenerateToStringWorker(clazz, editor, insertAtOverride).execute(selectedMemebers, template); } catch (Exception e) { - GenerateToStringUtils.handleExeption(clazz.getProject(), e); + GenerateToStringUtils.handleException(clazz.getProject(), e); } } }); diff --git a/plugins/git4idea/git4idea.iml b/plugins/git4idea/git4idea.iml index 733b2cb41b6a..6b8c1cb32ef8 100644 --- a/plugins/git4idea/git4idea.iml +++ b/plugins/git4idea/git4idea.iml @@ -34,6 +34,7 @@ + diff --git a/plugins/git4idea/rt/git4idea-rt.iml b/plugins/git4idea/rt/git4idea-rt.iml new file mode 100644 index 000000000000..62b44f66acf7 --- /dev/null +++ b/plugins/git4idea/rt/git4idea-rt.iml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/GitSSHHandler.java b/plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/GitSSHHandler.java similarity index 99% rename from plugins/git4idea/src/org/jetbrains/git4idea/ssh/GitSSHHandler.java rename to plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/GitSSHHandler.java index ae9384fd46fd..c5ed99e20966 100644 --- a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/GitSSHHandler.java +++ b/plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/GitSSHHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/GitSSHXmlRpcClient.java b/plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/GitSSHXmlRpcClient.java similarity index 98% rename from plugins/git4idea/src/org/jetbrains/git4idea/ssh/GitSSHXmlRpcClient.java rename to plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/GitSSHXmlRpcClient.java index 83d9cd325aaa..0f2f668a5caf 100644 --- a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/GitSSHXmlRpcClient.java +++ b/plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/GitSSHXmlRpcClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -83,7 +83,7 @@ public class GitSSHXmlRpcClient implements GitSSHHandler { * @return full method name */ private static String methodName(@NonNls final String method) { - return HANDLER_NAME + "." + method; + return GitSSHHandler.HANDLER_NAME + "." + method; } /** diff --git a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/SSHConfig.java b/plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/SSHConfig.java similarity index 99% rename from plugins/git4idea/src/org/jetbrains/git4idea/ssh/SSHConfig.java rename to plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/SSHConfig.java index 00a065da7114..5799db2270f4 100644 --- a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/SSHConfig.java +++ b/plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/SSHConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. diff --git a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/SSHMain.java b/plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/SSHMain.java similarity index 97% rename from plugins/git4idea/src/org/jetbrains/git4idea/ssh/SSHMain.java rename to plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/SSHMain.java index 85b67ce944ca..858a2d3e0317 100644 --- a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/SSHMain.java +++ b/plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/SSHMain.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -15,8 +15,8 @@ */ package org.jetbrains.git4idea.ssh; -import com.intellij.openapi.util.io.FileUtilLight; -import com.intellij.util.ArrayUtil; +import com.intellij.openapi.util.io.FileUtilRt; +import com.intellij.util.ArrayUtilRt; import com.trilead.ssh2.*; import com.trilead.ssh2.crypto.PEMDecoder; import org.jetbrains.annotations.NonNls; @@ -302,7 +302,7 @@ public class SSHMain { if (file.exists()) { // if encrypted ask user for passphrase String passphrase = null; - char[] text = FileUtilLight.loadFileText(file); + char[] text = FileUtilRt.loadFileText(file); if (isEncryptedKey(text)) { // need to ask passphrase from user int i; @@ -368,7 +368,7 @@ public class SSHMain { String line; while ((line = in.readLine()) != null) { //noinspection HardCodedStringLiteral - if (line.startsWith("Proc-Type: ") && line.indexOf("ENCRYPTED") != -1) { + if (line.startsWith("Proc-Type: ") && line.contains("ENCRYPTED")) { return true; } if (line.length() == 0) { @@ -445,7 +445,7 @@ public class SSHMain { database.addHostkeys(knownHostFile); } final List algorithms = myHost.getHostKeyAlgorithms(); - c.setServerHostKeyAlgorithms(ArrayUtil.toStringArray(algorithms)); + c.setServerHostKeyAlgorithms(ArrayUtilRt.toStringArray(algorithms)); } /** @@ -506,7 +506,7 @@ public class SSHMain { final String[] prompt, final boolean[] echo) throws Exception { if (numPrompts == 0) { - return ArrayUtil.EMPTY_STRING_ARRAY; + return ArrayUtilRt.EMPTY_STRING_ARRAY; } myPromptCount++; Vector vPrompts = new Vector(prompt.length); @@ -524,7 +524,7 @@ public class SSHMain { return rc; } else { - return ArrayUtil.toStringArray(result); + return ArrayUtilRt.toStringArray(result); } } } diff --git a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/SSHMainBundle.java b/plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/SSHMainBundle.java similarity index 90% rename from plugins/git4idea/src/org/jetbrains/git4idea/ssh/SSHMainBundle.java rename to plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/SSHMainBundle.java index 0a5122fc9b9c..507d1fc52919 100644 --- a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/SSHMainBundle.java +++ b/plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/SSHMainBundle.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -15,7 +15,7 @@ */ package org.jetbrains.git4idea.ssh; -import com.intellij.CommonBundle; +import com.intellij.BundleBase; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.PropertyKey; @@ -32,11 +32,10 @@ public class SSHMainBundle { @NonNls private static final String BUNDLE = "org.jetbrains.git4idea.ssh.SSHMainBundle"; - private SSHMainBundle() { - } + private SSHMainBundle() { } public static String message(@PropertyKey(resourceBundle = BUNDLE) String key, Object... params) { - return CommonBundle.message(getBundle(), key, params); + return BundleBase.message(getBundle(), key, params); } private static ResourceBundle getBundle() { @@ -52,5 +51,4 @@ public class SSHMainBundle { public static String getString(@PropertyKey(resourceBundle = BUNDLE) final String key) { return getBundle().getString(key); } - } diff --git a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/SSHMainBundle.properties b/plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/SSHMainBundle.properties similarity index 100% rename from plugins/git4idea/src/org/jetbrains/git4idea/ssh/SSHMainBundle.properties rename to plugins/git4idea/rt/src/org/jetbrains/git4idea/ssh/SSHMainBundle.properties diff --git a/plugins/git4idea/src/git4idea/actions/GitCompareWithBranchAction.java b/plugins/git4idea/src/git4idea/actions/GitCompareWithBranchAction.java index 45c32dbddf20..925cd756b38d 100644 --- a/plugins/git4idea/src/git4idea/actions/GitCompareWithBranchAction.java +++ b/plugins/git4idea/src/git4idea/actions/GitCompareWithBranchAction.java @@ -142,7 +142,11 @@ public class GitCompareWithBranchAction extends DumbAwareAction { if (repository == null || repository.isFresh() || noBranchesToCompare(repository)) { presentation.setEnabled(false); presentation.setVisible(true); + return; } + + presentation.setEnabled(true); + presentation.setVisible(true); } private static boolean noBranchesToCompare(@NotNull GitRepository repository) { diff --git a/plugins/git4idea/src/git4idea/actions/GitInit.java b/plugins/git4idea/src/git4idea/actions/GitInit.java index 78291cd44878..43aa23976177 100644 --- a/plugins/git4idea/src/git4idea/actions/GitInit.java +++ b/plugins/git4idea/src/git4idea/actions/GitInit.java @@ -15,6 +15,7 @@ */ package git4idea.actions; +import com.intellij.notification.NotificationType; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.components.ServiceManager; @@ -30,12 +31,12 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsDirectoryMapping; -import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsFileUtil; import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.commands.Git; +import git4idea.commands.GitCommandResult; import git4idea.i18n.GitBundle; import git4idea.util.GitUIUtil; import org.jetbrains.annotations.NotNull; @@ -78,13 +79,13 @@ public class GitInit extends DumbAwareAction { } } - GitVcs vcs = GitVcs.getInstance(project); Git git = ServiceManager.getService(Git.class); - try { - git.init(project, root); - } catch (VcsException ex) { - if (vcs == null || vcs.getExecutableValidator().isExecutableValid()) { - GitUIUtil.showOperationErrors(project, Collections.singleton(ex), "git init"); + GitVcs vcs = GitVcs.getInstance(project); + GitCommandResult result = git.init(project, root); + if (!result.success()) { + if (vcs != null && vcs.getExecutableValidator().isExecutableValid()) { + GitUIUtil.notify(GitVcs.IMPORTANT_ERROR_NOTIFICATION, project, "Git init failed", result.getErrorOutputAsHtmlString(), + NotificationType.ERROR, null); } return; } diff --git a/plugins/git4idea/src/git4idea/commands/Git.java b/plugins/git4idea/src/git4idea/commands/Git.java index b0e303723376..a4dfbb727e37 100644 --- a/plugins/git4idea/src/git4idea/commands/Git.java +++ b/plugins/git4idea/src/git4idea/commands/Git.java @@ -33,7 +33,7 @@ import java.util.Set; */ public interface Git { - void init(Project project, VirtualFile root) throws VcsException; + GitCommandResult init(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLineHandlerListener... listeners); @NotNull Set untrackedFiles(@NotNull Project project, diff --git a/plugins/git4idea/src/git4idea/commands/GitImpl.java b/plugins/git4idea/src/git4idea/commands/GitImpl.java index 56dfb31eb1d6..f610113b1cbe 100644 --- a/plugins/git4idea/src/git4idea/commands/GitImpl.java +++ b/plugins/git4idea/src/git4idea/commands/GitImpl.java @@ -50,17 +50,15 @@ public class GitImpl implements Git { /** * Calls 'git init' on the specified directory. - * // TODO use common format */ @Override - public void init(Project project, VirtualFile root) throws VcsException { - GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.INIT); - h.setSilent(false); - h.setNoSSH(true); - h.run(); - if (!h.errors().isEmpty()) { - throw h.errors().get(0); + public GitCommandResult init(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLineHandlerListener... listeners) { + GitLineHandler h = new GitLineHandler(project, root, GitCommand.INIT); + for (GitLineHandlerListener listener : listeners) { + h.addLineListener(listener); } + h.setSilent(false); + return run(h); } /** diff --git a/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java b/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java index c2a2213a141d..23decfea9335 100644 --- a/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java +++ b/plugins/git4idea/src/git4idea/history/browser/CherryPicker.java @@ -103,11 +103,11 @@ public class CherryPicker { public void run() { moveToCorrectLists(); } - }, InvokeAfterUpdateMode.SYNCHRONOUS_CANCELLABLE, "", new Consumer() { + }, InvokeAfterUpdateMode.SILENT, "", new Consumer() { public void consume(VcsDirtyScopeManager vcsDirtyScopeManager) { vcsDirtyScopeManager.filePathsDirty(getAllChangedFiles(), null); } - }, ModalityState.defaultModalityState()); + }, ModalityState.NON_MODAL); } private void showResults() { diff --git a/plugins/git4idea/src/git4idea/roots/GitIntegrationEnabler.java b/plugins/git4idea/src/git4idea/roots/GitIntegrationEnabler.java index ae1765dc4aaa..145ea231095a 100644 --- a/plugins/git4idea/src/git4idea/roots/GitIntegrationEnabler.java +++ b/plugins/git4idea/src/git4idea/roots/GitIntegrationEnabler.java @@ -20,13 +20,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsDirectoryMapping; -import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ui.UIUtil; import git4idea.Notificator; import git4idea.PlatformFacade; import git4idea.commands.Git; +import git4idea.commands.GitCommandResult; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -77,15 +77,15 @@ public class GitIntegrationEnabler { } private boolean gitInitOrNotifyError(@NotNull Notificator notificator, @NotNull final VirtualFile projectDir) { - try { - myGit.init(myProject, projectDir); + GitCommandResult result = myGit.init(myProject, projectDir); + if (result.success()) { refreshGitDir(projectDir); notificator.notifySuccess("", "Created Git repository in \n" + projectDir.getPresentableUrl()); return true; } - catch (VcsException e) { - notificator.notifyError("Couldn't git init " + projectDir.getPresentableUrl(), e.getMessage()); - LOG.error(e); + else { + notificator.notifyError("Couldn't git init " + projectDir.getPresentableUrl(), result.getErrorOutputAsHtmlString()); + LOG.info(result.getErrorOutputAsHtmlString()); return false; } } diff --git a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/GitSSHService.java b/plugins/git4idea/src/org/jetbrains/git4idea/ssh/GitSSHService.java index 389254f3ab8a..c262e41d4266 100644 --- a/plugins/git4idea/src/org/jetbrains/git4idea/ssh/GitSSHService.java +++ b/plugins/git4idea/src/org/jetbrains/git4idea/ssh/GitSSHService.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -15,7 +15,6 @@ */ package org.jetbrains.git4idea.ssh; -import com.intellij.openapi.util.io.FileUtilLight; import com.trilead.ssh2.KnownHosts; import gnu.trove.THashMap; import org.apache.commons.codec.DecoderException; @@ -23,6 +22,7 @@ import org.apache.xmlrpc.XmlRpcClientLite; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.git4idea.util.ScriptGenerator; +import com.intellij.openapi.util.io.FileUtilRt; import java.io.File; import java.io.IOException; @@ -66,8 +66,7 @@ public abstract class GitSSHService { public synchronized File getScriptPath() throws IOException { if (myScriptPath == null || !myScriptPath.exists()) { ScriptGenerator generator = new ScriptGenerator(GitSSHHandler.GIT_SSH_PREFIX, SSHMain.class, getTempDir()); - generator.addClasses(XmlRpcClientLite.class, DecoderException.class); - generator.addClasses(KnownHosts.class, FileUtilLight.class); + generator.addClasses(XmlRpcClientLite.class, DecoderException.class, KnownHosts.class, FileUtilRt.class); generator.addResource(SSHMainBundle.class, "/org/jetbrains/git4idea/ssh/SSHMainBundle.properties"); myScriptPath = generator.generate(); } diff --git a/plugins/git4idea/src/org/jetbrains/git4idea/util/ScriptGenerator.java b/plugins/git4idea/src/org/jetbrains/git4idea/util/ScriptGenerator.java index b754a56493e6..ffdb80c526cd 100644 --- a/plugins/git4idea/src/org/jetbrains/git4idea/util/ScriptGenerator.java +++ b/plugins/git4idea/src/org/jetbrains/git4idea/util/ScriptGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -17,11 +17,11 @@ package org.jetbrains.git4idea.util; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.io.FileUtilLight; import com.intellij.util.PathUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; +import com.intellij.openapi.util.io.FileUtilRt; import java.io.File; import java.io.FileWriter; @@ -149,8 +149,8 @@ public class ScriptGenerator { */ @SuppressWarnings({"HardCodedStringLiteral"}) public File generate() throws IOException { - File scriptPath = myTempDir != null ? FileUtilLight.createTempFile(myTempDir, myPrefix, SCRIPT_EXT, true) - : FileUtilLight.createTempFile(myPrefix, SCRIPT_EXT); + File scriptPath = myTempDir != null ? FileUtilRt.createTempFile(myTempDir, myPrefix, SCRIPT_EXT, true) + : FileUtilRt.createTempFile(myPrefix, SCRIPT_EXT); scriptPath.deleteOnExit(); PrintWriter out = new PrintWriter(new FileWriter(scriptPath)); try { @@ -172,7 +172,7 @@ public class ScriptGenerator { finally { out.close(); } - FileUtilLight.setExecutableAttribute(scriptPath.getPath(), true); + FileUtilRt.setExecutableAttribute(scriptPath.getPath(), true); return scriptPath; } diff --git a/plugins/git4idea/tests/git4idea/test/MockGit.groovy b/plugins/git4idea/tests/git4idea/test/MockGit.groovy index a90770008384..fb6497932119 100644 --- a/plugins/git4idea/tests/git4idea/test/MockGit.groovy +++ b/plugins/git4idea/tests/git4idea/test/MockGit.groovy @@ -22,6 +22,7 @@ import git4idea.commands.GitCommandResult import git4idea.commands.GitLineHandlerListener import git4idea.push.GitPushSpec import git4idea.repo.GitRepository +import org.jetbrains.annotations.NotNull /** * @@ -30,8 +31,9 @@ import git4idea.repo.GitRepository class MockGit implements Git { @Override - void init(Project project, VirtualFile root) { + GitCommandResult init(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLineHandlerListener... listeners) { new File(root.path, ".git").mkdir() + new GitCommandResult(true, 0, Collections.emptyList(), Collections.emptyList()) } @Override diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java index 1903933b61e2..d306f0b6e297 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java @@ -7,6 +7,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationInfoEx; +import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -17,12 +18,10 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.VcsOutgoingChangesProvider; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.ChangeListManagerImpl; import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode; import com.intellij.openapi.vcs.changes.actions.RefreshAction; -import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.concurrency.Semaphore; @@ -32,11 +31,13 @@ import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.actions.BasicAction; import git4idea.actions.GitInit; -import git4idea.push.GitPushUtils; import git4idea.commands.*; import git4idea.i18n.GitBundle; -import git4idea.util.GitUIUtil; +import git4idea.push.GitPushUtils; +import git4idea.repo.GitRepository; +import git4idea.repo.GitRepositoryManager; import git4idea.util.GitFileUtils; +import git4idea.util.GitUIUtil; import org.jetbrains.plugins.github.ui.GithubShareDialog; import java.io.IOException; @@ -129,12 +130,13 @@ public class GithubShareAction extends DumbAwareAction { Messages.showErrorDialog(e1.getMessage(), "Failed to create new GitHub repository"); return; } - bindToGithub(project, root, gitDetected, settings.getLogin(), name); - Notifications.Bus.notify(new Notification("github", "Success", "Successfully created project ''" + name + "'' on github", - NotificationType.INFORMATION)); + if (bindToGithub(project, root, gitDetected, settings.getLogin(), name)) { + Notifications.Bus.notify(new Notification("github", "Success", "Successfully created project ''" + name + "'' on github", + NotificationType.INFORMATION)); + } } - private void bindToGithub(final Project project, final VirtualFile root, final boolean gitDetected, final String login, final String name) { + private boolean bindToGithub(final Project project, final VirtualFile root, final boolean gitDetected, final String login, String name) { LOG.info("Binding local project with GitHub"); // creating empty git repo if git isnot initialized if (!gitDetected) { @@ -145,7 +147,7 @@ public class GithubShareAction extends DumbAwareAction { if (!h.errors().isEmpty()) { GitUIUtil.showOperationErrors(project, h.errors(), "git init"); LOG.info("Failed to create empty git repo: " + h.errors()); - return; + return false; } final ProgressManager manager = ProgressManager.getInstance(); manager.runProcessWithProgressSynchronously(new Runnable() { @@ -157,7 +159,9 @@ public class GithubShareAction extends DumbAwareAction { } // In this case we should create sample commit for binding project - performFirstCommitIfRequired(project, root); + if (!performFirstCommitIfRequired(project, root)) { + return false; + } //git remote add origin git@github.com:login/name.git LOG.info("Adding GitHub as a remote host"); @@ -169,13 +173,13 @@ public class GithubShareAction extends DumbAwareAction { addRemoteHandler.run(); if (addRemoteHandler.getExitCode() != 0) { Messages.showErrorDialog("Failed to add GitHub repository as remote", "Failed to add GitHub repository as remote"); - return; + return false; } } catch (VcsException e) { Messages.showErrorDialog(e.getMessage(), "Failed to add GitHub repository as remote"); LOG.info("Failed to add GitHub as remote: " + e.getMessage()); - return; + return false; } //git push origin master @@ -198,6 +202,7 @@ public class GithubShareAction extends DumbAwareAction { } // refresh vcs manually RefreshAction.doRefresh(project); + return true; } private boolean performFirstCommitIfRequired(final Project project, final VirtualFile root) { @@ -206,20 +211,21 @@ public class GithubShareAction extends DumbAwareAction { Messages.showErrorDialog(project, "Cannot find git initialized", "Failed to share"); return false; } - final VcsOutgoingChangesProvider provider = gitVcs.getOutgoingChangesProvider(); - if (provider == null) { - Messages.showErrorDialog(project, "Cannot find git initialized", "Failed to share"); + + GitRepositoryManager repositoryManager = ServiceManager.getService(project, GitRepositoryManager.class); + Git git = ServiceManager.getService(Git.class); + if (repositoryManager == null || git == null) { return false; } - try { - if (!provider.getOutgoingChanges(root, false).getSecond().isEmpty()){ - return true; - } - } - catch (VcsException e) { - Messages.showErrorDialog(project, e.getMessage(), "Failed to share"); + GitRepository repository = repositoryManager.getRepositoryForRoot(root); + if (repository == null) { + Messages.showErrorDialog(project, "Cannot find git repository for root " + root, "Failed to share"); return false; } + if (!repository.isFresh()) { + return true; + } + final Ref exceptionRef = new Ref(); // Creating or modifying readme file LOG.info("Touching file 'README' for initial commit"); diff --git a/plugins/groovy/resources/inspectionDescriptions/GroovyUnusedAssignment.html b/plugins/groovy/resources/inspectionDescriptions/GroovyUnusedAssignment.html index f10ac59f3c47..d093014e3eab 100644 --- a/plugins/groovy/resources/inspectionDescriptions/GroovyUnusedAssignment.html +++ b/plugins/groovy/resources/inspectionDescriptions/GroovyUnusedAssignment.html @@ -2,6 +2,6 @@ This inspection reports on unnecessary Groovy assignment statement -
Powered by InspectorGroovy +
diff --git a/plugins/groovy/resources/inspectionDescriptions/GroovyUnusedIncOrDec.html b/plugins/groovy/resources/inspectionDescriptions/GroovyUnusedIncOrDec.html new file mode 100644 index 000000000000..13ba5a2d65e5 --- /dev/null +++ b/plugins/groovy/resources/inspectionDescriptions/GroovyUnusedIncOrDec.html @@ -0,0 +1,6 @@ + + +This inspection reports on unnecessary Groovy incrementing and decrementing expressions +
+ + diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index f16a34ca5f0c..956a30ddf366 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -408,6 +408,9 @@ + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties index c3735295a072..57c820df5558 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties @@ -302,3 +302,5 @@ method.with.type.parameters.should.have.return.type=Method with type parameters primitive.type.parameters.are.not.allowed=Primitive type parameters are not allowed primitive.bound.types.are.not.allowed=Primitive bound types are not allowed ellipsis.type.is.not.allowed.here=Ellipsis type is not allowed here +method.0.is.too.complex.too.analyze=Method ''{0}'' is too complex to analyze.\nTypes of local variables are not inferred. +closure.is.too.complex.to.analyze=Closure is complex to analyze.\nTypes of local variables are not inferred. diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/DumpGroovyControlFlowAction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/DumpGroovyControlFlowAction.java index 856b586a76c6..46f6694f41fd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/DumpGroovyControlFlowAction.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/DumpGroovyControlFlowAction.java @@ -82,6 +82,7 @@ public class DumpGroovyControlFlowAction extends AnAction implements DumbAware { } private static void passInner(GrControlFlowOwner owner) { + System.out.println(owner.getText()); System.out.println(ControlFlowUtils.dumpControlFlow(owner.getControlFlow())); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index 4858ab7eae7a..a9ff9c221209 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -99,6 +99,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatem import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.types.*; import org.jetbrains.plugins.groovy.lang.psi.api.util.GrVariableDeclarationOwner; +import org.jetbrains.plugins.groovy.lang.psi.impl.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil; @@ -290,7 +291,8 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { for (PsiReference reference : ReferencesSearch.search(var, new LocalSearchScope(scope)).findAll()) { if (reference instanceof GrReferenceExpression && (PsiUtil.isLValue((GrReferenceExpression)reference) || - ((GrReferenceExpression)reference).getParent() instanceof GrPostfixExpression)) { + ((GrReferenceExpression)reference).getParent() instanceof GrUnaryExpression && + ((GrUnaryExpression)((GrReferenceExpression)reference).getParent()).isPostfix())) { if (hasAssignment) { return true; } @@ -531,6 +533,12 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { checkMethodWithTypeParamsShouldHaveReturnType(myHolder, method); checkInnerMethod(myHolder, method); checkMethodParameters(myHolder, method); + + GrOpenBlock block = method.getBlock(); + if (block != null && TypeInferenceHelper.isTooComplexTooAnalyze(block)) { + myHolder.createWeakWarningAnnotation(method.getNameIdentifierGroovy(), GroovyBundle.message("method.0.is.too.complex.too.analyze", + method.getName())); + } } private static void checkMethodWithTypeParamsShouldHaveReturnType(AnnotationHolder holder, GrMethod method) { @@ -935,6 +943,20 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { if (!closure.hasParametersSection() && isClosureAmbiguous(closure)) { myHolder.createErrorAnnotation(closure, GroovyBundle.message("ambiguous.code.block")); } + + if (TypeInferenceHelper.isTooComplexTooAnalyze(closure)) { + int startOffset = closure.getLBrace().getTextRange().getStartOffset(); + int endOffset; + if (closure.getArrow()!=null) { + endOffset = closure.getArrow().getTextRange().getEndOffset(); + } + else { + String text = + PsiDocumentManager.getInstance(closure.getProject()).getDocument(closure.getContainingFile()).getText(); + endOffset = Math.min(closure.getTextRange().getEndOffset(), text.indexOf('\n', startOffset)); + } + myHolder.createWeakWarningAnnotation(new TextRange(startOffset, endOffset), GroovyBundle.message("closure.is.too.complex.to.analyze")); + } } private static boolean isClosureAmbiguous(GrClosableBlock closure) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties index b650ca7468de..28f439a39a95 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties @@ -35,6 +35,8 @@ groovy.dfa.issues=Data Flow Issues unused.assignment=Unused Assignment unused.assignment.tooltip=Assignment is not used +unused.inc.dec=Unused Incrementing or Decrementing + unassigned.access=Variable Not Assigned unassigned.access.short.name=VariableNotAssigned unassigned.access.tooltip=Variable ''{0}'' might not be assigned @@ -77,3 +79,7 @@ rtype.cannot.contain.ltype=''{1}'' cannot contain ''{0}'' new.instance.of.singleton=New instance of class annotated with @groovy.lang.Singleton replace.new.expression.with.0.instance=Replace with ''{0}.instance'' getter.0.clashes.with.getter.1={0} clashes with {1} +unused.0=Unused {0} +remove.0=Remove {0} +replace.postfix.0.with.prefix.0=Replace postfix {0} with prefix {0} +replace.0.with.1=Replace {0} with binary {1} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyLocalInspectionBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyLocalInspectionBase.java index d22a439132a4..c46ea77c0c87 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyLocalInspectionBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyLocalInspectionBase.java @@ -22,6 +22,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementVisitor; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrClassInitializer; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; @@ -42,7 +43,6 @@ public abstract class GroovyLocalInspectionBase extends GroovySuppressableInspec return new GroovyPsiElementVisitor(new GroovyElementVisitor() { public void visitClosure(GrClosableBlock closure) { check(closure, problemsHolder); - } public void visitMethod(GrMethod method) { @@ -55,6 +55,11 @@ public abstract class GroovyLocalInspectionBase extends GroovySuppressableInspec public void visitFile(GroovyFileBase file) { check(file, problemsHolder); } + + @Override + public void visitClassInitializer(GrClassInitializer initializer) { + check(initializer.getBlock(), problemsHolder); + } }); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GrUnusedIncDecInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GrUnusedIncDecInspection.java new file mode 100644 index 000000000000..fadb994f0ec0 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GrUnusedIncDecInspection.java @@ -0,0 +1,241 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.codeInspection.confusing; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.codeInspection.BaseInspection; +import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; +import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle; +import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; +import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; + +import java.util.Iterator; +import java.util.List; + +/** + * @author Max Medvedev + */ +public class GrUnusedIncDecInspection extends BaseInspection { + private static final Logger LOG = Logger.getInstance(GrUnusedIncDecInspection.class); + @Override + protected BaseInspectionVisitor buildVisitor() { + return new GrUnusedIncDecInspectionVisitor(); + } + + @Override + public boolean isEnabledByDefault() { + return true; + } + + @Nls + @NotNull + public String getGroupDisplayName() { + return GroovyInspectionBundle.message("groovy.dfa.issues"); + } + + @Nls + @NotNull + public String getDisplayName() { + return GroovyInspectionBundle.message("unused.inc.dec"); + } + + @NonNls + @NotNull + public String getShortName() { + return "GroovyUnusedIncOrDec"; + } + + private static class GrUnusedIncDecInspectionVisitor extends BaseInspectionVisitor { + @Override + public void visitUnaryExpression(GrUnaryExpression expression) { + super.visitUnaryExpression(expression); + + IElementType opType = expression.getOperationTokenType(); + if (opType != GroovyTokenTypes.mINC && opType != GroovyTokenTypes.mDEC) return; + + GrExpression operand = expression.getOperand(); + if (!(operand instanceof GrReferenceExpression)) return; + + PsiElement resolved = ((GrReferenceExpression)operand).resolve(); + if (!(resolved instanceof GrVariable) || resolved instanceof GrField) return; + + final GrControlFlowOwner owner = ControlFlowUtils.findControlFlowOwner(expression); + assert owner != null; + GrControlFlowOwner ownerOfDeclaration = ControlFlowUtils.findControlFlowOwner(resolved); + if (ownerOfDeclaration != owner) return; + + final Instruction cur = ControlFlowUtils.findInstruction(operand, owner.getControlFlow()); + + if (cur == null) { + LOG.error("no instruction found in flow." + "operand: " + operand.getText() + " cfo: " + owner.getText()); + } + + //get write access for inc or dec + Iterable successors = cur.allSuccessors(); + Iterator iterator = successors.iterator(); + LOG.assertTrue(iterator.hasNext()); + Instruction writeAccess = iterator.next(); + LOG.assertTrue(!iterator.hasNext()); + + List accesses = ControlFlowUtils.findAccess((GrVariable)resolved, true, false, writeAccess); + + boolean allAreWrite = true; + for (ReadWriteVariableInstruction access : accesses) { + if (!access.isWrite()) { + allAreWrite = false; + break; + } + } + + + if (allAreWrite) { + if (expression.isPostfix() && PsiUtil.isExpressionUsed(expression)) { + registerError(expression.getOperationToken(), + GroovyInspectionBundle.message("unused.0", expression.getOperationToken().getText()), + new LocalQuickFix[]{new ReplacePostfixIncWithPrefixFix(expression), new RemoveIncOrDecFix(expression)}, + ProblemHighlightType.LIKE_UNUSED_SYMBOL); + } + else if (!PsiUtil.isExpressionUsed(expression)) { + registerError(expression.getOperationToken(), + GroovyInspectionBundle.message("unused.0", expression.getOperationToken().getText()), LocalQuickFix.EMPTY_ARRAY, + ProblemHighlightType.LIKE_UNUSED_SYMBOL); + } + } + } + + private static class RemoveIncOrDecFix implements LocalQuickFix { + private final String myMessage; + + public RemoveIncOrDecFix(GrUnaryExpression expression) { + myMessage = GroovyInspectionBundle.message("remove.0", expression.getOperationToken().getText()); + } + + @NotNull + @Override + public String getName() { + return myMessage; + } + + @NotNull + @Override + public String getFamilyName() { + return myMessage; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + GrUnaryExpression expr = findUnaryExpression(descriptor); + if (expr == null) return; + + expr.replaceWithExpression(expr.getOperand(), true); + } + } + + private static class ReplacePostfixIncWithPrefixFix implements LocalQuickFix { + private final String myMessage; + + public ReplacePostfixIncWithPrefixFix(GrUnaryExpression expression) { + myMessage = GroovyInspectionBundle.message("replace.postfix.0.with.prefix.0", expression.getOperationToken().getText()); + } + + @NotNull + @Override + public String getName() { + return myMessage; + } + + @NotNull + @Override + public String getFamilyName() { + return myMessage; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + GrUnaryExpression expr = findUnaryExpression(descriptor); + if (expr == null) return; + + GrExpression prefix = GroovyPsiElementFactory.getInstance(project) + .createExpressionFromText(expr.getOperationToken().getText() + expr.getOperand().getText()); + + expr.replaceWithExpression(prefix, true); + } + } + + private static class ReplaceIncDecWithBinary implements LocalQuickFix { + private final String myMessage; + + public ReplaceIncDecWithBinary(GrUnaryExpression expression) { + String opToken = expression.getOperationToken().getText(); + myMessage = GroovyInspectionBundle.message("replace.0.with.1", opToken, opToken.substring(0, 1)); + } + + @NotNull + @Override + public String getName() { + return myMessage; + } + + @NotNull + @Override + public String getFamilyName() { + return myMessage; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + GrUnaryExpression expr = findUnaryExpression(descriptor); + GrExpression newExpr = GroovyPsiElementFactory.getInstance(project) + .createExpressionFromText(expr.getOperand().getText() + expr.getOperationToken().getText().substring(0, 1) + "1"); + expr.replaceWithExpression(newExpr, true); + } + } + } + + @Nullable + private static GrUnaryExpression findUnaryExpression(ProblemDescriptor descriptor) { + GrUnaryExpression expr; + PsiElement element = descriptor.getPsiElement(); + if (element == null) return null; + PsiElement parent = element.getParent(); + IElementType opType = element.getNode().getElementType(); + if (opType != GroovyTokenTypes.mINC && opType != GroovyTokenTypes.mDEC) return null; + if (!(parent instanceof GrUnaryExpression)) return null; + expr = (GrUnaryExpression)parent; + return expr; + } +} + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/threading/GroovyWhileLoopSpinsOnFieldInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/threading/GroovyWhileLoopSpinsOnFieldInspection.java index 01548294a59b..a7429db7e476 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/threading/GroovyWhileLoopSpinsOnFieldInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/threading/GroovyWhileLoopSpinsOnFieldInspection.java @@ -30,7 +30,10 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrBlockStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrWhileStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import javax.swing.*; @@ -94,9 +97,8 @@ public class GroovyWhileLoopSpinsOnFieldInspection extends BaseInspection { return true; } - if (condition instanceof GrPostfixExpression) { - final GrPostfixExpression postfixExpression = - (GrPostfixExpression) condition; + if (condition instanceof GrUnaryExpression && ((GrUnaryExpression)condition).isPostfix()) { + final GrUnaryExpression postfixExpression = (GrUnaryExpression) condition; final GrExpression operand = postfixExpression.getOperand(); return isSimpleFieldComparison(operand); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/unusedDef/UnusedDefInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/unusedDef/UnusedDefInspection.java index fb8e2f0e6c12..4bb6ad43dfae 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/unusedDef/UnusedDefInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/unusedDef/UnusedDefInspection.java @@ -24,7 +24,7 @@ import com.intellij.psi.PsiReference; import com.intellij.psi.impl.DebugUtil; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.tree.IElementType; import com.intellij.util.Processor; import gnu.trove.TIntHashSet; import gnu.trove.TIntObjectHashMap; @@ -33,28 +33,25 @@ import gnu.trove.TObjectProcedure; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle; import org.jetbrains.plugins.groovy.codeInspection.GroovyLocalInspectionBase; +import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrClassInitializer; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrPostfixExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAEngine; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsDfaInstance; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsSemilattice; -import java.util.ArrayList; +import java.util.List; /** & @author ven @@ -86,7 +83,11 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase { final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow); final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice(); final DFAEngine> engine = new DFAEngine>(flow, dfaInstance, lattice); - final ArrayList> dfaResult = engine.performDFA(); + final List> dfaResult = engine.performDFAWithTimeout(); + if (dfaResult == null) { + return; + } + final TIntHashSet unusedDefs = new TIntHashSet(); for (Instruction instruction : flow) { if (instruction instanceof ReadWriteVariableInstruction && ((ReadWriteVariableInstruction) instruction).isWrite()) { @@ -97,9 +98,9 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase { for (int i = 0; i < dfaResult.size(); i++) { final Instruction instruction = flow[i]; if (instruction instanceof ReadWriteVariableInstruction) { - final ReadWriteVariableInstruction varInsn = (ReadWriteVariableInstruction) instruction; - if (!varInsn.isWrite()) { - final String varName = varInsn.getVariableName(); + final ReadWriteVariableInstruction varInst = (ReadWriteVariableInstruction) instruction; + if (!varInst.isWrite()) { + final String varName = varInst.getVariableName(); TIntObjectHashMap e = dfaResult.get(i); e.forEachValue(new TObjectProcedure() { public boolean execute(TIntHashSet reaching) { @@ -124,21 +125,8 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase { final ReadWriteVariableInstruction instruction = (ReadWriteVariableInstruction)flow[num]; final PsiElement element = instruction.getElement(); if (element == null) return true; - PsiElement toHighlight = null; - if (isLocalAssignment(element) && isUsedInToplevelFlowOnly(element)) { - if (element instanceof GrReferenceExpression) { - PsiElement parent = element.getParent(); - if (parent instanceof GrAssignmentExpression) { - toHighlight = ((GrAssignmentExpression)parent).getLValue(); - } - if (parent instanceof GrPostfixExpression) { - toHighlight = parent; - } - } - else if (element instanceof GrVariable) { - toHighlight = ((GrVariable)element).getNameIdentifierGroovy(); - } - if (toHighlight == null) toHighlight = element; + if (isLocalAssignment(element) && isUsedInTopLevelFlowOnly(element) && !isIncOrDec(element)) { + PsiElement toHighlight = getHighlightElement(element); problemsHolder.registerProblem(toHighlight, GroovyInspectionBundle.message("unused.assignment.tooltip"), ProblemHighlightType.LIKE_UNUSED_SYMBOL); } @@ -147,25 +135,52 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase { }); } - private static boolean isUsedInToplevelFlowOnly(PsiElement element) { + private static PsiElement getHighlightElement(PsiElement element) { + PsiElement toHighlight = null; + if (element instanceof GrReferenceExpression) { + PsiElement parent = element.getParent(); + if (parent instanceof GrAssignmentExpression) { + toHighlight = ((GrAssignmentExpression)parent).getLValue(); + } + if (parent instanceof GrUnaryExpression && ((GrUnaryExpression)parent).isPostfix()) { + toHighlight = parent; + } + } + else if (element instanceof GrVariable) { + toHighlight = ((GrVariable)element).getNameIdentifierGroovy(); + } + if (toHighlight == null) toHighlight = element; + return toHighlight; + } + + private static boolean isIncOrDec(PsiElement element) { + PsiElement parent = element.getParent(); + if (!(parent instanceof GrUnaryExpression)) return false; + + IElementType type = ((GrUnaryExpression)parent).getOperationTokenType(); + return type == GroovyTokenTypes.mINC || type == GroovyTokenTypes.mDEC; + } + + private static boolean isUsedInTopLevelFlowOnly(PsiElement element) { GrVariable var = null; if (element instanceof GrVariable) { - var = (GrVariable) element; - } else if (element instanceof GrReferenceExpression) { - final PsiElement resolved = ((GrReferenceExpression) element).resolve(); - if (resolved instanceof GrVariable) var = (GrVariable) resolved; + var = (GrVariable)element; + } + else if (element instanceof GrReferenceExpression) { + final PsiElement resolved = ((GrReferenceExpression)element).resolve(); + if (resolved instanceof GrVariable) var = (GrVariable)resolved; } if (var != null) { - final GroovyPsiElement scope = getScope(var); + final GroovyPsiElement scope = ControlFlowUtils.findControlFlowOwner(var); if (scope == null) { PsiFile file = var.getContainingFile(); - LOG.error(file == null ? "no file??? var of type"+ var.getClass().getCanonicalName() : DebugUtil.psiToString(file, true, false)); + LOG.error(file == null ? "no file??? var of type" + var.getClass().getCanonicalName() : DebugUtil.psiToString(file, true, false)); } return ReferencesSearch.search(var, new LocalSearchScope(scope)).forEach(new Processor() { public boolean process(PsiReference ref) { - return getScope(ref.getElement()) == scope; + return ControlFlowUtils.findControlFlowOwner(ref.getElement()) == scope; } }); } @@ -173,17 +188,14 @@ public class UnusedDefInspection extends GroovyLocalInspectionBase { return true; } - @Nullable - private static GroovyPsiElement getScope(PsiElement var) { - return PsiTreeUtil.getContextOfType(var, GrClosableBlock.class, GrMethod.class, GrClassInitializer.class, GroovyFileBase.class); - } private static boolean isLocalAssignment(PsiElement element) { if (element instanceof GrVariable) { - return isLocalVariable((GrVariable) element, false); - } else if (element instanceof GrReferenceExpression) { - final PsiElement resolved = ((GrReferenceExpression) element).resolve(); - return resolved instanceof GrVariable && isLocalVariable((GrVariable) resolved, true); + return isLocalVariable((GrVariable)element, false); + } + else if (element instanceof GrReferenceExpression) { + final PsiElement resolved = ((GrReferenceExpression)element).resolve(); + return resolved instanceof GrVariable && isLocalVariable((GrVariable)resolved, true); } return false; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java index 36583cf8bba0..bd663678c098 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java @@ -40,7 +40,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnState import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrPostfixExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; @@ -54,7 +53,6 @@ import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAEngine; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DfaInstance; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.Semilattice; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; -import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; import java.util.*; @@ -155,17 +153,13 @@ public class ControlFlowUtils { if (openBlockMayCompleteNormally(tryBlock)) { return true; } - final GrCatchClause[] catchClauses = tryStatement.getCatchClauses(); - if (catchClauses != null) { - - for (GrCatchClause catchClause : catchClauses) { - if (openBlockMayCompleteNormally(catchClause.getBody())) { - return true; - } + for (GrCatchClause catchClause : tryStatement.getCatchClauses()) { + if (openBlockMayCompleteNormally(catchClause.getBody())) { + return true; } - } + return false; } @@ -499,7 +493,6 @@ public class ControlFlowUtils { public static boolean isIncOrDecOperand(GrReferenceExpression referenceExpression) { final PsiElement parent = referenceExpression.getParent(); - if (parent instanceof GrPostfixExpression) return true; if (parent instanceof GrUnaryExpression) { final IElementType opType = ((GrUnaryExpression)parent).getOperationTokenType(); return opType == GroovyTokenTypes.mDEC || opType == GroovyTokenTypes.mINC; @@ -650,10 +643,11 @@ public class ControlFlowUtils { @Nullable public static GrControlFlowOwner findControlFlowOwner(PsiElement place) { if (place instanceof GrCodeBlock) { - place = place.getParent(); + place = place.getContext(); } while (true) { - place = place.getParent(); + assert place != null; + place = place.getContext(); if (place == null) return null; if (place instanceof GrClosableBlock) return (GrClosableBlock)place; if (place instanceof GrMethod) return ((GrMethod)place).getBlock(); @@ -675,22 +669,28 @@ public class ControlFlowUtils { } public static List findAccess(GrVariable local, final PsiElement place, boolean ahead, boolean writeAccessOnly) { - LOG.assertTrue(GroovyRefactoringUtil.isLocalVariable(local), local.getClass()); + LOG.assertTrue(!(local instanceof GrField), local.getClass()); final GrControlFlowOwner owner = findControlFlowOwner(local); assert owner != null; final Instruction cur = findInstruction(place, owner.getControlFlow()); - if (cur == null) throw new IllegalArgumentException("place is not in the flow"); + if (cur == null) { + throw new IllegalArgumentException("place is not in the flow"); + } + return findAccess(local, ahead, writeAccessOnly, cur); + } + + public static List findAccess(GrVariable local, boolean ahead, boolean writeAccessOnly, Instruction cur) { String name = local.getName(); - + final ArrayList result = new ArrayList(); final HashSet visited = new HashSet(); - + visited.add(cur); - + Queue queue = new ArrayDeque(); for (Instruction i : ahead ? cur.allSuccessors() : cur.allPredecessors()) { @@ -698,11 +698,11 @@ public class ControlFlowUtils { queue.add(i); } } - + while (true) { Instruction instruction = queue.poll(); if (instruction == null) break; - + if (instruction instanceof ReadWriteVariableInstruction) { ReadWriteVariableInstruction rw = (ReadWriteVariableInstruction)instruction; if (name.equals(rw.getVariableName())) { @@ -710,13 +710,13 @@ public class ControlFlowUtils { result.add(rw); continue; } - + if (!writeAccessOnly) { result.add(rw); } } } - + for (Instruction i : ahead ? instruction.allSuccessors() : instruction.allPredecessors()) { if (visited.add(i)) { queue.add(i); @@ -726,9 +726,9 @@ public class ControlFlowUtils { return result; } - + @Nullable - private static Instruction findInstruction(final PsiElement place, Instruction[] controlFlow) { + public static Instruction findInstruction(final PsiElement place, Instruction[] controlFlow) { return ContainerUtil.find(controlFlow, new Condition() { @Override public boolean value(Instruction instruction) { @@ -737,6 +737,7 @@ public class ControlFlowUtils { }); } + @NotNull public static ArrayList inferWriteAccessMap(final Instruction[] flow, final GrVariable var) { final Semilattice sem = new Semilattice() { @@ -787,7 +788,7 @@ public class ControlFlowUtils { } }; - return new DFAEngine(flow, dfa, sem).performDFA(); + return new DFAEngine(flow, dfa, sem).performForceDFA(); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/EquivalenceChecker.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/EquivalenceChecker.java index fdde5dd99efd..c67351f4dced 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/EquivalenceChecker.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/EquivalenceChecker.java @@ -445,8 +445,8 @@ public class EquivalenceChecker { return prefixExpressionsAreEquivalent((GrUnaryExpression) expToCompare1, (GrUnaryExpression) expToCompare2); case POSTFIX_EXPRESSION: - return postfixExpressionsAreEquivalent((GrPostfixExpression) expToCompare1, - (GrPostfixExpression) expToCompare2); + return postfixExpressionsAreEquivalent((GrUnaryExpression) expToCompare1, + (GrUnaryExpression) expToCompare2); case BINARY_EXPRESSION: return binaryExpressionsAreEquivalent((GrBinaryExpression) expToCompare1, (GrBinaryExpression) expToCompare2); @@ -674,8 +674,8 @@ public class EquivalenceChecker { return expressionsAreEquivalent(operand1, operand2); } - private static boolean postfixExpressionsAreEquivalent(@NotNull GrPostfixExpression postfixExp1, - @NotNull GrPostfixExpression postfixExp2) { + private static boolean postfixExpressionsAreEquivalent(@NotNull GrUnaryExpression postfixExp1, + @NotNull GrUnaryExpression postfixExp2) { final IElementType sign1 = postfixExp1.getOperationTokenType(); final IElementType sign2 = postfixExp2.getOperationTokenType(); if (!sign1.equals(sign2)) { @@ -690,7 +690,7 @@ public class EquivalenceChecker { @NotNull GrBinaryExpression binaryExp2) { final IElementType sign1 = binaryExp1.getOperationTokenType(); final IElementType sign2 = binaryExp2.getOperationTokenType(); - if (sign1 == null || sign2 == null || !sign1.equals(sign2)) { + if (!sign1.equals(sign2)) { return false; } final GrExpression lhs1 = binaryExp1.getLeftOperand(); @@ -834,11 +834,8 @@ public class EquivalenceChecker { if (exp instanceof GrMethodCall) { return CALL_EXPRESSION; } - if (exp instanceof GrPostfixExpression) { - return POSTFIX_EXPRESSION; - } if (exp instanceof GrUnaryExpression) { - return PREFIX_EXPRESSION; + return ((GrUnaryExpression)exp).isPostfix() ? POSTFIX_EXPRESSION : PREFIX_EXPRESSION; } if (exp instanceof GrAssignmentExpression) { return ASSIGNMENT_EXPRESSION; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/SideEffectChecker.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/SideEffectChecker.java index 13cc60aaf959..6f4946169677 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/SideEffectChecker.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/SideEffectChecker.java @@ -20,7 +20,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; public class SideEffectChecker { @@ -71,19 +74,6 @@ public class SideEffectChecker { mayHaveSideEffects = true; } - public void visitPostfixExpression( - @NotNull GrPostfixExpression expression) { - if (mayHaveSideEffects) { - return; - } - super.visitPostfixExpression(expression); - final IElementType tokenType = expression.getOperationTokenType(); - if (tokenType.equals(GroovyTokenTypes.mINC) || - tokenType.equals(GroovyTokenTypes.mDEC)) { - mayHaveSideEffects = true; - } - } - public void visitUnaryExpression( @NotNull GrUnaryExpression expression) { if (mayHaveSideEffects) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerBase.java index 9c0ee98046b6..d546b64d0ebc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/GroovyCompilerBase.java @@ -165,38 +165,40 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler { parameters.setMainClass(GroovycRunner.class.getName()); - try { - final VirtualFile finalOutputDir = getMainOutput(compileContext, module, tests); - LOG.assertTrue(finalOutputDir != null, "No output directory for module " + module.getName() + (tests ? " tests" : " production")); - final Charset ideCharset = EncodingProjectManager.getInstance(myProject).getDefaultCharset(); - String encoding = ideCharset != null && !Comparing.equal(CharsetToolkit.getDefaultSystemCharset(), ideCharset) ? ideCharset.name() : null; - Set paths2Compile = ContainerUtil.map2Set(toCompile, new Function() { - @Override - public String fun(VirtualFile file) { - return file.getPath(); - } - }); - Map class2Src = new HashMap(); + final VirtualFile finalOutputDir = getMainOutput(compileContext, module, tests); + LOG.assertTrue(finalOutputDir != null, "No output directory for module " + module.getName() + (tests ? " tests" : " production")); + final Charset ideCharset = EncodingProjectManager.getInstance(myProject).getDefaultCharset(); + String encoding = ideCharset != null && !Comparing.equal(CharsetToolkit.getDefaultSystemCharset(), ideCharset) ? ideCharset.name() : null; + Set paths2Compile = ContainerUtil.map2Set(toCompile, new Function() { + @Override + public String fun(VirtualFile file) { + return file.getPath(); + } + }); + Map class2Src = new HashMap(); - for (VirtualFile file : enumerateGroovyFiles(module)) { - if (!paths2Compile.contains(file.getPath())) { - for (String name : TranslatingCompilerFilesMonitor.getInstance().getCompiledClassNames(file, myProject)) { - class2Src.put(name, file.getPath()); - } + for (VirtualFile file : enumerateGroovyFiles(module)) { + if (!paths2Compile.contains(file.getPath())) { + for (String name : TranslatingCompilerFilesMonitor.getInstance().getCompiledClassNames(file, myProject)) { + class2Src.put(name, file.getPath()); } } + } - File fileWithParameters = GroovycOSProcessHandler + final File fileWithParameters; + try { + fileWithParameters = GroovycOSProcessHandler .fillFileWithGroovycParameters(outputDir.getPath(), paths2Compile, FileUtil.toSystemDependentName(finalOutputDir.getPath()), class2Src, encoding, patchers); - - parameters.getProgramParametersList().add(forStubs ? "stubs" : "groovyc"); - parameters.getProgramParametersList().add(fileWithParameters.getPath()); } catch (IOException e) { - LOG.error(e); + LOG.info(e); + compileContext.addMessage(CompilerMessageCategory.ERROR, "Error creating a temp file to launch Groovy compiler: " + e.getMessage(), null, -1, -1); + return; } + parameters.getProgramParametersList().add(forStubs ? "stubs" : "groovyc"); + parameters.getProgramParametersList().add(fileWithParameters.getPath()); try { Process process = JdkUtil.setupJVMCommandLine(exePath, parameters, true).createProcess(); @@ -272,7 +274,8 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler { sink.add(outputDir.getPath(), items, VfsUtil.toVirtualFileArray(toRecompile)); } catch (ExecutionException e) { - LOG.error(e); + LOG.info(e); + compileContext.addMessage(CompilerMessageCategory.ERROR, "Error running Groovy compiler: " + e.getMessage(), null, -1, -1); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java index 18c08d51d08a..970d869780a1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java @@ -484,17 +484,8 @@ public class GroovySpacingProcessor extends GroovyElementVisitor { @Override public void visitUnaryExpression(GrUnaryExpression expression) { - //prefix only - LOG.assertTrue(!(expression instanceof GrPostfixExpression)); - - if (expression.getOperationToken() == myChild1) { - createSpaceInCode(mySettings.SPACE_AROUND_UNARY_OPERATOR); - } - } - - @Override - public void visitPostfixExpression(GrPostfixExpression expression) { - if (expression.getOperationToken() == myChild2) { + if (!expression.isPostfix() && expression.getOperationToken() == myChild1 || + expression.isPostfix() && expression.getOperationToken() == myChild2) { createSpaceInCode(mySettings.SPACE_AROUND_UNARY_OPERATOR); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/utils/ParenthesesUtils.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/utils/ParenthesesUtils.java index cf87e09df314..4c354de1c83a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/utils/ParenthesesUtils.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/utils/ParenthesesUtils.java @@ -104,17 +104,14 @@ public class ParenthesesUtils { expression instanceof GrNewExpression) { return TYPE_CAST_PRECEDENCE; } - if (expression instanceof GrPostfixExpression) { - return POSTFIX_PRECEDENCE; - } if (expression instanceof GrUnaryExpression) { - return PREFIX_PRECEDENCE; + return ((GrUnaryExpression)expression).isPostfix()?POSTFIX_PRECEDENCE:PREFIX_PRECEDENCE; } if (expression instanceof GrBinaryExpression) { final GrBinaryExpression binaryExpression = (GrBinaryExpression) expression; final IElementType sign = binaryExpression.getOperationTokenType(); - if (sign != null) return precedenceForBinaryOperator(sign); + return precedenceForBinaryOperator(sign); } if (expression instanceof GrConditionalExpression) { return CONDITIONAL_PRECEDENCE; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java index b04214d900aa..d09ec7ff336d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java @@ -201,14 +201,4 @@ public abstract class TokenSets { ); public static final TokenSet SHIFT_SIGNS = TokenSet.create(COMPOSITE_LSHIFT_SIGN, COMPOSITE_RSHIFT_SIGN, COMPOSITE_TRIPLE_SHIFT_SIGN); - - public static final TokenSet POSTFIXES = TokenSet.create(mINC,mDEC); - public static final TokenSet PREFIXES = TokenSet.create( - mPLUS, - mMINUS, - mINC, - mDEC, - mBNOT, - mLNOT - ); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java index e1d73e4cc191..0ecc5f9e99f6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java @@ -222,7 +222,6 @@ public interface GroovyElementTypes extends GroovyTokenTypes, GroovyDocElementTy GroovyElementType CAST_EXPRESSION = new GroovyElementType("cast expression"); GroovyElementType SAFE_CAST_EXPRESSION = new GroovyElementType("safe cast expression"); GroovyElementType INSTANCEOF_EXPRESSION = new GroovyElementType("instanceof expression"); - GroovyElementType POSTFIX_EXPRESSION = new GroovyElementType("Postfix expression"); GroovyElementType PATH_PROPERTY_REFERENCE = new GroovyElementType("Property reference"); GroovyElementType PATH_METHOD_CALL = new GroovyElementType("Method call"); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java index 30c697c579a0..6f5d0be5057f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java @@ -28,7 +28,10 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyASTPsiElementImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrLabelImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrListOrMapImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrThrowsClauseImpl; -import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.*; +import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationArgumentListImpl; +import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationArrrayInitializerImpl; +import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationImpl; +import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationNameValuePairImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.modifiers.GrModifierListImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.*; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.arguments.GrArgumentLabelImpl; @@ -218,7 +221,6 @@ public class GroovyPsiCreator implements GroovyElementTypes { if (elem == POWER_EXPRESSION) return new GrPowerExpressionImpl(node); if (elem == POWER_EXPRESSION_SIMPLE) return new GrPowerExpressionImpl(node); if (elem == UNARY_EXPRESSION) return new GrUnaryExpressionImpl(node); - if (elem == POSTFIX_EXPRESSION) return new GrPostfixExprImpl(node); if (elem == CAST_EXPRESSION) return new GrTypeCastExpressionImpl(node); if (elem == SAFE_CAST_EXPRESSION) return new GrSafeCastExpressionImpl(node); if (elem == INSTANCEOF_EXPRESSION) return new GrInstanceofExpressionImpl(node); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PostfixExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PostfixExpression.java index e8edbafc9d0b..5ab5c9efd0a9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PostfixExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/PostfixExpression.java @@ -40,9 +40,9 @@ public class PostfixExpression implements GroovyElementTypes { } private static void subParse(PsiBuilder builder, PsiBuilder.Marker marker) { - if (ParserUtils.getToken(builder, TokenSets.POSTFIXES)) { + if (ParserUtils.getToken(builder, TokenSets.POSTFIX_UNARY_OP_SET)) { PsiBuilder.Marker newMarker = marker.precede(); - marker.done(POSTFIX_EXPRESSION); + marker.done(UNARY_EXPRESSION); subParse(builder, newMarker); } else { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/UnaryExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/UnaryExpression.java index 64d4a3c3c515..d215334597f7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/UnaryExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/UnaryExpression.java @@ -30,7 +30,7 @@ public class UnaryExpression implements GroovyElementTypes { public static boolean parse(PsiBuilder builder, GroovyParser parser) { PsiBuilder.Marker marker = builder.mark(); - if (ParserUtils.getToken(builder, TokenSets.PREFIXES)) { + if (ParserUtils.getToken(builder, TokenSets.UNARY_OP_SET)) { ParserUtils.getToken(builder, mNLS); parse(builder, parser); marker.done(UNARY_EXPRESSION); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java index cdd57b7486ec..872546b7894a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java @@ -168,10 +168,6 @@ public abstract class GroovyElementVisitor { visitExpression(expression); } - public void visitPostfixExpression(GrPostfixExpression expression) { - visitUnaryExpression(expression); - } - public void visitRegexExpression(GrRegex expression) { visitGStringExpression(expression); } @@ -443,4 +439,8 @@ public abstract class GroovyElementVisitor { public void visitTypeParameterList(GrTypeParameterList list) { visitElement(list); } + + public void visitClassInitializer(GrClassInitializer initializer) { + visitElement(initializer); + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrUnaryExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrUnaryExpression.java index ef4a8b6b5b85..03900c94f287 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrUnaryExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrUnaryExpression.java @@ -35,4 +35,6 @@ public interface GrUnaryExpression extends GrExpression, PsiPolyVariantReference @NotNull @Override GroovyResolveResult[] multiResolve(final boolean incompleteCode); + + boolean isPostfix(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReadWriteVariableInstruction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReadWriteVariableInstruction.java index 247cdd929346..e68eddd8fa56 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReadWriteVariableInstruction.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ReadWriteVariableInstruction.java @@ -23,13 +23,16 @@ import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.InstructionImpl; * @author ven */ public class ReadWriteVariableInstruction extends InstructionImpl { + public static final int WRITE = -1; + public static final int READ = 1; + private final boolean myIsWrite; private final String myName; - public ReadWriteVariableInstruction(@NotNull String varName, PsiElement element, int num, boolean isWrite) { + public ReadWriteVariableInstruction(@NotNull String varName, PsiElement element, int num, int accessType) { super(element, num); myName = varName; - myIsWrite = isWrite; + myIsWrite = accessType == WRITE; } @NotNull public String getVariableName() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java index 2e4f31e52201..1fea9d257838 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; @@ -51,6 +52,9 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import java.util.*; +import static org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction.READ; +import static org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction.WRITE; + /** * @author ven */ @@ -107,7 +111,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { final PsiElement lbrace = block.getLBrace(); if (lbrace != null && parent instanceof GrMethod) { for (GrParameter parameter : ((GrMethod)parent).getParameters()) { - addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, true)); + addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, WRITE)); } } super.visitOpenBlock(block); @@ -185,7 +189,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { private void buildFlowForClosure(final GrClosableBlock closure) { for (GrParameter parameter : closure.getAllParameters()) { - addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, true)); + addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, WRITE)); } final Set names = new LinkedHashSet(); @@ -207,7 +211,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { names.add("owner"); for (String name : names) { - addNode(new ReadWriteVariableInstruction(name, closure.getLBrace(), myInstructionNumber++, true)); + addNode(new ReadWriteVariableInstruction(name, closure.getLBrace(), myInstructionNumber++, WRITE)); } PsiElement child = closure.getFirstChild(); @@ -241,12 +245,26 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { //do not go inside closures except gstring injections if (closure.getParent() instanceof GrStringInjection) { super.visitClosure(closure); + return; } - else { - //create instruction for closure to use it in inline local refactoring - final InstructionImpl i = new InstructionImpl(closure, myInstructionNumber++); + + Set names = new HashSet(); + + ReadWriteVariableInstruction[] reads = ControlFlowBuilderUtil.getReadsWithoutPriorWrites(closure.getControlFlow()); + for (ReadWriteVariableInstruction read : reads) { + names.add(read.getVariableName()); + } + + for (String name : names) { + ReadWriteVariableInstruction i = new ReadWriteVariableInstruction(name, closure, myInstructionNumber++, READ); addNode(i); + checkPending(i); } + + + InstructionImpl i = new InstructionImpl(closure, myInstructionNumber++); + addNode(i); + checkPending(i); } public void visitBreakStatement(GrBreakStatement breakStatement) { @@ -364,7 +382,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { if (lValue instanceof GrReferenceExpression) { String referenceName = ((GrReferenceExpression)lValue).getReferenceName(); if (referenceName != null) { - ReadWriteVariableInstruction instruction = new ReadWriteVariableInstruction(referenceName, lValue, myInstructionNumber++, false); + ReadWriteVariableInstruction instruction = new ReadWriteVariableInstruction(referenceName, lValue, myInstructionNumber++, READ); addNode(instruction); checkPending(instruction); } @@ -413,17 +431,14 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { if (name == null) return; if (ControlFlowUtils.isIncOrDecOperand(refExpr) && !myAssertionsOnly) { - final ReadWriteVariableInstruction i = new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, false); + final InstructionImpl i = new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, READ); addNode(i); - addNode(new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, true)); - if (refExpr.getParent() instanceof GrUnaryExpression) { - addNode(new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, false)); - } + addNode(new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, WRITE)); checkPending(i); } else { - final ReadWriteVariableInstruction i = - new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, !myAssertionsOnly && PsiUtil.isLValue(refExpr)); + boolean isWrite = !myAssertionsOnly && PsiUtil.isLValue(refExpr); + final InstructionImpl i = new ReadWriteVariableInstruction(name, refExpr, myInstructionNumber++, isWrite ? WRITE : READ); addNode(i); checkPending(i); } @@ -563,10 +578,10 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { } GrVariable variable = clause.getDeclaredVariable(); if (variable != null) { - ReadWriteVariableInstruction writeInsn = - new ReadWriteVariableInstruction(variable.getName(), variable, myInstructionNumber++, true); - checkPending(writeInsn); - addNode(writeInsn); + ReadWriteVariableInstruction writeInst = + new ReadWriteVariableInstruction(variable.getName(), variable, myInstructionNumber++, WRITE); + checkPending(writeInst); + addNode(writeInst); } } @@ -755,6 +770,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { Set> pendingAfterTry = new LinkedHashSet>(myPending); + @SuppressWarnings("unchecked") List[] throwers = new List[catchClauses.length]; for (int i = 0; i < catchClauses.length; i++) { @@ -772,7 +788,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { final GrParameter parameter = catchClauses[i].getParameter(); if (parameter != null) { - addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, true)); + addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, myInstructionNumber++, WRITE)); } catchClauses[i].accept(this); catches[i] = myHead; @@ -867,19 +883,73 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { public void visitMethod(GrMethod method) { } - public void visitTypeDefinition(GrTypeDefinition typeDefinition) { - if (typeDefinition instanceof GrAnonymousClassDefinition) { - super.visitTypeDefinition(typeDefinition); + @Override + public void visitClassInitializer(GrClassInitializer initializer) { + } + + public void visitTypeDefinition(final GrTypeDefinition typeDefinition) { + if (!(typeDefinition instanceof GrAnonymousClassDefinition)) return; + + final Set vars = new HashSet(); + typeDefinition.acceptChildren(new GroovyRecursiveElementVisitor() { + private void collectVars(Instruction[] flow) { + ReadWriteVariableInstruction[] reads = ControlFlowBuilderUtil.getReadsWithoutPriorWrites(flow); + for (ReadWriteVariableInstruction instruction : reads) { + vars.add(instruction.getVariableName()); + } + } + + @Override + public void visitField(GrField field) { + GrExpression initializer = field.getInitializerGroovy(); + if (initializer != null) { + Instruction[] flow = new ControlFlowBuilder(field.getProject()).buildControlFlow(initializer); + collectVars(flow); + } + } + + @Override + public void visitMethod(GrMethod method) { + GrOpenBlock block = method.getBlock(); + if (block != null) { + collectVars(block.getControlFlow()); + } + } + + @Override + public void visitClassInitializer(GrClassInitializer initializer) { + GrOpenBlock block = initializer.getBlock(); + collectVars(block.getControlFlow()); + } + + @Override + public void visitTypeDefinition(GrTypeDefinition typeDefinition) { + typeDefinition.acceptChildren(this); + } + }); + + PsiField[] fields = typeDefinition.getAllFields(); + for (PsiField field : fields) { + vars.remove(field.getName()); } + + for (String var : vars) { + ReadWriteVariableInstruction i = new ReadWriteVariableInstruction(var, typeDefinition, myInstructionNumber++, READ); + addNode(i); + checkPending(i); + } + InstructionImpl i = new InstructionImpl(typeDefinition, myInstructionNumber++); + addNode(i); + checkPending(i); } public void visitVariable(GrVariable variable) { super.visitVariable(variable); if (variable.getInitializerGroovy() != null || variable.getParent() instanceof GrTupleDeclaration && ((GrTupleDeclaration)variable.getParent()).getInitializerGroovy() != null) { - ReadWriteVariableInstruction writeInsn = new ReadWriteVariableInstruction(variable.getName(), variable, myInstructionNumber++, true); - checkPending(writeInsn); - addNode(writeInsn); + ReadWriteVariableInstruction writeInst = new ReadWriteVariableInstruction(variable.getName(), variable, myInstructionNumber++, WRITE); + checkPending(writeInst); + addNode(writeInst); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java index 72e975a3b555..0db8157ec869 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java @@ -16,6 +16,8 @@ package org.jetbrains.plugins.groovy.lang.psi.dataFlow; import com.intellij.openapi.progress.ProgressManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.CallEnvironment; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.CallInstruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ControlFlowBuilderUtil; @@ -27,6 +29,8 @@ import java.util.*; * @author ven */ public class DFAEngine { + private static final long ourTimeLimit = 1000; + private final Instruction[] myFlow; private final DfaInstance myDfa; @@ -57,7 +61,22 @@ public class DFAEngine { } } - public ArrayList performDFA() { + @NotNull + public ArrayList performForceDFA() { + ArrayList result = performDFA(false); + assert result != null; + return result; + } + + @Nullable + public ArrayList performDFAWithTimeout() { + return performDFA(true); + } + + @Nullable + private ArrayList performDFA(boolean timeout) { + long startTime = System.currentTimeMillis(); + ArrayList info = new ArrayList(myFlow.length); CallEnvironment env = new MyCallEnvironment(myFlow.length); for (int i = 0; i < myFlow.length; i++) { @@ -78,6 +97,8 @@ public class DFAEngine { visited[instr.num()] = true; while (!workList.isEmpty()) { + if (timeout && System.currentTimeMillis() - startTime > ourTimeLimit) return null; + ProgressManager.checkCanceled(); final Instruction curr = workList.remove(); final int num = curr.num(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java index ad34f71449f4..4ebd0621742f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java @@ -53,6 +53,7 @@ public class ReachingDefinitionsCollector { private ReachingDefinitionsCollector() { } + @NotNull public static FragmentVariableInfos obtainVariableFlowInformation(final GrStatement first, final GrStatement last) { GroovyPsiElement context = PsiTreeUtil.getParentOfType(first, GrMethod.class, GrClosableBlock.class, GroovyFileBase.class, GrClassInitializer.class); GrControlFlowOwner flowOwner; @@ -66,7 +67,7 @@ public class ReachingDefinitionsCollector { final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow); final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice(); final DFAEngine> engine = new DFAEngine>(flow, dfaInstance, lattice); - final TIntObjectHashMap dfaResult = postprocess(engine.performDFA(), flow, dfaInstance); + final TIntObjectHashMap dfaResult = postprocess(engine.performForceDFA(), flow, dfaInstance); final LinkedHashSet fragmentInstructions = getFragmentInstructions(first, last, flow); final int[] postorder = ControlFlowBuilderUtil.postorder(flow); @@ -149,16 +150,15 @@ public class ReachingDefinitionsCollector { } String name = variable.getName(); - if (name != null) { - if (!(variable instanceof GrField)) { - if (!isInFragment(first, last, resolved)) { - if (isInFragment(first, last, closure)) { - addVariable(name, imap, variable.getManager(), variable.getType()); - } - } else { - if (!isInFragment(first, last, closure)) { - addVariable(name, omap, variable.getManager(), variable.getType()); - } + if (!(variable instanceof GrField)) { + if (!isInFragment(first, last, resolved)) { + if (isInFragment(first, last, closure)) { + addVariable(name, imap, variable.getManager(), variable.getType()); + } + } + else { + if (!isInFragment(first, last, closure)) { + addVariable(name, omap, variable.getManager(), variable.getType()); } } } @@ -306,7 +306,7 @@ public class ReachingDefinitionsCollector { final StringBuffer buffer = new StringBuffer(); for (int i = 0; i < dfaResult.size(); i++) { TIntObjectHashMap map = dfaResult.get(i); - buffer.append("At " + i + ":\n"); + buffer.append("At ").append(i).append(":\n"); map.forEachEntry(new TIntObjectProcedure() { public boolean execute(int i, TIntHashSet defs) { buffer.append(i).append(" -> "); @@ -366,7 +366,10 @@ public class ReachingDefinitionsCollector { } } - private static TIntObjectHashMap postprocess(final ArrayList> dfaResult, Instruction[] flow, ReachingDefinitionsDfaInstance dfaInstance) { + @NotNull + private static TIntObjectHashMap postprocess(@NotNull final ArrayList> dfaResult, + @NotNull Instruction[] flow, + @NotNull ReachingDefinitionsDfaInstance dfaInstance) { TIntObjectHashMap result = new TIntObjectHashMap(); for (int i = 0; i < flow.length; i++) { Instruction insn = flow[i]; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java index f837f3687ec3..22d5d9ad691d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java @@ -39,7 +39,6 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.formatter.GeeseUtil; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.psi.GrNamedElement; import org.jetbrains.plugins.groovy.lang.psi.GrQualifiedReference; @@ -317,15 +316,13 @@ public class PsiImplUtil { private static int getExprPriorityLevel(GrExpression expr) { int priority = 0; //if (expr instanceof GrNewExpression) priority = 1; - if (expr instanceof GrPostfixExpression) priority = 5; - else if (expr instanceof GrUnaryExpression || - expr instanceof GrTypeCastExpression) priority = 6; + if (expr instanceof GrUnaryExpression) priority = ((GrUnaryExpression)expr).isPostfix() ? 5 : 6; + else if (expr instanceof GrTypeCastExpression) priority = 6; else if (expr instanceof GrRangeExpressionImpl) priority = 11; else if (expr instanceof GrBinaryExpression) { final IElementType opToken = ((GrBinaryExpression)expr).getOperationTokenType(); - LOG.assertTrue(opToken != null, expr.getText()); if (opToken == mSTAR_STAR) priority = 7; else if (opToken == mSTAR || opToken == mDIV) priority = 8; @@ -507,7 +504,7 @@ public class PsiImplUtil { } else { if (oldQualifier == null) { if (refNameElement != null) { - node.addLeaf(GroovyTokenTypes.mDOT, ".", refNameElement.getNode()); + node.addLeaf(mDOT, ".", refNameElement.getNode()); ref.addBefore(newQualifier, refNameElement.getPrevSibling()); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java index edc9c60ee6c4..ddcbd868464c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/TypeInferenceHelper.java @@ -89,6 +89,10 @@ public class TypeInferenceHelper { return getInferredType(variableName, instruction, flow, scope); } + public static boolean isTooComplexTooAnalyze(GrControlFlowOwner scope) { + return getDefUseMaps(scope).second == null; + } + @Nullable private static Instruction findInstructionAt(PsiElement place, Instruction[] flow) { List applicable = new ArrayList(); @@ -131,7 +135,10 @@ public class TypeInferenceHelper { final Pair>> pair = getDefUseMaps(scope); final int varIndex = pair.first.getVarIndex(varName); - final TIntObjectHashMap allDefs = pair.second.get(instruction.num()); + List> second = pair.second; + if (second == null) return null; + + final TIntObjectHashMap allDefs = second.get(instruction.num()); final TIntHashSet varDefs = allDefs.get(varIndex); if (varDefs == null) return null; @@ -174,7 +181,7 @@ public class TypeInferenceHelper { }; final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice(); final DFAEngine> engine = new DFAEngine>(flow, dfaInstance, lattice); - final List> dfaResult = engine.performDFA(); + final List> dfaResult = engine.performDFAWithTimeout(); return Result.create(Pair.create(dfaInstance, dfaResult), PsiModificationTracker.MODIFICATION_COUNT); } }); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrClassInitializerImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrClassInitializerImpl.java index ab2d9984d740..623daf3e780f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrClassInitializerImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrClassInitializerImpl.java @@ -25,6 +25,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; +import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrClassInitializer; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; @@ -42,6 +43,11 @@ public class GrClassInitializerImpl extends GroovyPsiElementImpl implements GrCl super(node); } + @Override + public void accept(GroovyElementVisitor visitor) { + visitor.visitClassInitializer(this); + } + public String toString() { return "Class initializer"; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrPostfixExprImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrPostfixExprImpl.java deleted file mode 100644 index f5f2092ad9be..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrPostfixExprImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.arithmetic; - -import com.intellij.lang.ASTNode; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrPostfixExpression; - -/** - * @author ilyas - */ -public class GrPostfixExprImpl extends GrUnaryExpressionImpl implements GrPostfixExpression { - - public GrPostfixExprImpl(@NotNull ASTNode node) { - super(node); - } - - public String toString() { - return "Postfix expression"; - } - - public void accept(GroovyElementVisitor visitor) { - visitor.visitPostfixExpression(this); - } -} \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java index 2b95343cbaef..3ae033a3a647 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java @@ -125,6 +125,11 @@ public class GrUnaryExpressionImpl extends GrExpressionImpl implements GrUnaryEx return (GroovyResolveResult[])ResolveCache.getInstance(getProject()).resolveWithCaching(this, OUR_RESOLVER, false, incompleteCode); } + @Override + public boolean isPostfix() { + return getFirstChild() instanceof GrExpression; + } + @Override public PsiElement getElement() { return this; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java index 239574da80c1..ce38cea5b7cd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java @@ -78,9 +78,9 @@ public class ResolveUtil { } /** - * + * * @param place - place to start tree walk up - * @param processor + * @param processor * @param processNonCodeMethods - this parameter tells us if we need non code members. But non code members are started to process only after we walk up any code block or script * @return */ @@ -95,10 +95,6 @@ public class ResolveUtil { while (run != null) { if (!run.processDeclarations(processor, ResolveState.initial(), lastParent, place)) return false; - if (run instanceof GrClosableBlock) { - PsiClass superClass = getLiteralSuperClass((GrClosableBlock)run); - if (superClass != null && !superClass.processDeclarations(processor, ResolveState.initial(), null, place)) return false; - } if (processNonCodeMethods) { if (!doProcessNonCodeMembers) { if (run instanceof GrCodeBlock) doProcessNonCodeMembers = true; @@ -115,6 +111,9 @@ public class ResolveUtil { } } else if (run instanceof GrClosableBlock) { + PsiClass superClass = getLiteralSuperClass((GrClosableBlock)run); + if (superClass != null && !superClass.processDeclarations(processor, ResolveState.initial(), null, place)) return false; + if (!GdkMethodUtil.categoryIteration((GrClosableBlock)run, processor)) return false; if (!GdkMethodUtil.withIteration((GrClosableBlock)run, processor, place)) return false; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java index b55c62da66d4..2a60c5494208 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java @@ -669,7 +669,7 @@ public class ExpressionGenerator extends Generator { @Override public void visitUnaryExpression(GrUnaryExpression expression) { - final boolean postfix = expression instanceof GrPostfixExpression; + final boolean postfix = expression.isPostfix(); final GroovyResolveResult resolveResult = PsiImplUtil.extractUniqueResult(expression.multiResolve(false)); final PsiElement resolved = resolveResult.getElement(); @@ -816,12 +816,12 @@ public class ExpressionGenerator extends Generator { private static void writeSimpleUnary(GrExpression operand, GrUnaryExpression unary, ExpressionGenerator generator) { String opTokenText = unary.getOperationToken().getText(); - boolean isPrefix = !(unary instanceof GrPostfixExpression); - if (isPrefix) { + boolean isPostfix = unary.isPostfix(); + if (!isPostfix) { generator.getBuilder().append(opTokenText); } operand.accept(generator); - if (!isPrefix) { + if (isPostfix) { generator.getBuilder().append(opTokenText); } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy index d4f6fe10a871..e0ba3cd80dad 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy @@ -37,6 +37,7 @@ import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilit import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyResultOfAssignmentUsedInspection import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyUncheckedAssignmentOfMemberOfRawTypeInspection import org.jetbrains.plugins.groovy.codeInspection.confusing.ClashingGettersInspection +import org.jetbrains.plugins.groovy.codeInspection.confusing.GrUnusedIncDecInspection import org.jetbrains.plugins.groovy.codeInspection.confusing.GroovyOctalIntegerInspection import org.jetbrains.plugins.groovy.codeInspection.confusing.GroovyResultOfIncrementOrDecrementUsedInspection import org.jetbrains.plugins.groovy.codeInspection.control.GroovyTrivialConditionalInspection @@ -188,10 +189,10 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { public void testUnassigned3() throws Exception { doTest(new UnassignedVariableAccessInspection()); } public void testUnassignedTryFinally() throws Exception { doTest(new UnassignedVariableAccessInspection()); } - public void testUnusedVariable() throws Exception { doTest(new UnusedDefInspection()); } - public void testDefinitionUsedInClosure() throws Exception { doTest(new UnusedDefInspection()); } - public void testDefinitionUsedInClosure2() throws Exception { doTest(new UnusedDefInspection()); } - public void testDefinitionUsedInSwitchCase() throws Exception { doTest(new UnusedDefInspection()); } + public void testUnusedVariable() throws Exception { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); } + public void testDefinitionUsedInClosure() throws Exception { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); } + public void testDefinitionUsedInClosure2() throws Exception { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); } + public void testDefinitionUsedInSwitchCase() throws Exception { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); } public void testDuplicateInnerClass() throws Throwable{doTest();} public void testThisInStaticContext() throws Throwable {doTest();} @@ -248,8 +249,8 @@ class A { public void testByteArrayArgument() throws Exception {doTest(new GroovyAssignabilityCheckInspection());} public void testForLoopWithNestedEndlessLoop() throws Exception {doTest(new UnassignedVariableAccessInspection());} - public void testPrefixIncrementCfa() throws Exception {doTest(new UnusedDefInspection());} - public void testIfIncrementElseReturn() throws Exception {doTest(new UnusedDefInspection()); } + public void testPrefixIncrementCfa() throws Exception {doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection());} + public void testIfIncrementElseReturn() throws Exception {doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); } public void testArrayLikeAccess() throws Exception {doTest();} @@ -315,7 +316,7 @@ class A { public void testBuiltInTypeInstantiation() {doTest();} - public void testSwitchControlFlow() {doTest(new UnusedDefInspection(), new GroovyResultOfAssignmentUsedInspection());} + public void testSwitchControlFlow() {doTest(new UnusedDefInspection(), new GroovyResultOfAssignmentUsedInspection(), new GrUnusedIncDecInspection());} public void testRawTypeInAssignment() {doTest(new GroovyAssignabilityCheckInspection());} @@ -325,7 +326,7 @@ class A { IdeaTestUtil.assertTiming("", 10000, 1, new Runnable() { @Override public void run() { - doTest(new GroovyAssignabilityCheckInspection(), new UnusedDefInspection()); + doTest(new GroovyAssignabilityCheckInspection(), new UnusedDefInspection(), new GrUnusedIncDecInspection()); } }); } @@ -397,7 +398,7 @@ class A { doTest(new GroovyUnresolvedAccessInspection(), new GroovyUntypedAccessInspection()); } - public void testUsageInInjection() { doTest(new UnusedDefInspection()); } + public void testUsageInInjection() { doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); } public void testDuplicatedNamedArgs() {doTest();} @@ -419,15 +420,19 @@ class A { } public void testUnusedDefsForArgs() { - doTest(new UnusedDefInspection()); + doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); } public void testUsedDefBeforeTry1() { - doTest(new UnusedDefInspection()); + doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); } public void testUsedDefBeforeTry2() { - doTest(new UnusedDefInspection()); + doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()); + } + + public void testUnusedInc() { + doTest(new UnusedDefInspection(), new GrUnusedIncDecInspection()) } public void testStringAssignableToChar() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.java index a6790d48e8d5..ff34da2ea32e 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.java @@ -55,6 +55,8 @@ public class ControlFlowTest extends LightCodeInsightFixtureTestCase { public void testIfInstanceofElse() throws Throwable { doTest(); } public void testReturnMapFromClosure() {doTest();} public void testSwitchInTryWithThrows() {doTest();} + public void testClosure() {doTest();} + public void testAnonymous() {doTest();} public void doTest() { final List input = TestUtils.readInput(getTestDataPath() + getTestName(true) + ".test"); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.groovy index 04fee16b1f12..729e0d436827 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.groovy @@ -114,4 +114,7 @@ public class ExtractMethodTest extends LightGroovyTestCase { public void testParamChangedInsideExtractedMethod() {doTest();} public void testTerribleAppStatement() {doTest()} + + public void testArgsUsedOnlyInClosure() {doTest()} + public void testArgsUsedOnlyInAnonymousClass() {doTest()} } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/anonymous.test b/plugins/groovy/testdata/groovy/controlFlow/anonymous.test new file mode 100644 index 000000000000..79b93ac0c3fd --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/anonymous.test @@ -0,0 +1,17 @@ +int x = 0 +[1, 2, 3].each (new Closure(this, this) { + void call() { + x++ + } +}) + +print x +----- +0(1) element: null +1(2) WRITE x +2(3) READ x +3(4) element: Anonymous class +4(5) READ print +5(6) READ x +6(7) element: Call expression MAYBE_RETURN +7() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/closure.test b/plugins/groovy/testdata/groovy/controlFlow/closure.test new file mode 100644 index 000000000000..ed94fc177ee3 --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/closure.test @@ -0,0 +1,15 @@ +int x = 0 +[1, 2, 3].each { + x++ +} + +print x +----- +0(1) element: null +1(2) WRITE x +2(3) READ x +3(4) element: Closable block +4(5) READ print +5(6) READ x +6(7) element: Call expression MAYBE_RETURN +7() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/for1.test b/plugins/groovy/testdata/groovy/controlFlow/for1.test index 0f0ebbd84c66..cefbd1ce77bf 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/for1.test +++ b/plugins/groovy/testdata/groovy/controlFlow/for1.test @@ -3,8 +3,7 @@ for(int i = 0; i < 10; i++); 0(1) element: null 1(2) WRITE i 2(3) element: For statement -3(4,7) READ i +3(4,6) READ i 4(5) READ i -5(6) WRITE i -6(2) READ i -7() element: null \ No newline at end of file +5(2) WRITE i +6() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/while1.test b/plugins/groovy/testdata/groovy/controlFlow/while1.test index 3b7578eb1411..493df467f932 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/while1.test +++ b/plugins/groovy/testdata/groovy/controlFlow/while1.test @@ -8,9 +8,8 @@ while (true) { 1(2) WRITE i 2(3) element: WHILE statement 3(4,5) element: IF statement -4(9) READ i +4(8) READ i 5(6) element: IF statement 6(7) READ i -7(8) WRITE i -8(2) READ i -9() element: null \ No newline at end of file +7(2) WRITE i +8() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/whileNonConstant.test b/plugins/groovy/testdata/groovy/controlFlow/whileNonConstant.test index a54fd3bee520..f1206ab03412 100644 --- a/plugins/groovy/testdata/groovy/controlFlow/whileNonConstant.test +++ b/plugins/groovy/testdata/groovy/controlFlow/whileNonConstant.test @@ -7,11 +7,10 @@ while (condition()) { 0(1) element: null 1(2) WRITE i 2(3) element: WHILE statement -3(4,10) READ condition +3(4,9) READ condition 4(5,6) element: IF statement -5(10) READ i +5(9) READ i 6(7) element: IF statement 7(8) READ i -8(9) WRITE i -9(2) READ i -10() element: null \ No newline at end of file +8(2) WRITE i +9() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/argsUsedOnlyInAnonymousClass.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/argsUsedOnlyInAnonymousClass.test new file mode 100644 index 000000000000..0857daf5c4db --- /dev/null +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/argsUsedOnlyInAnonymousClass.test @@ -0,0 +1,19 @@ +def foo(b, c) { + [].each (new Closure(this, this) { + void call() { + b.plus(c) + } + }) +} +----- +def foo(b, c) { + testMethod(b, c) +} + +private testMethod(b, c) { + [].each(new Closure(this, this) { + void call() { + b.plus(c) + } + }) +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/argsUsedOnlyInClosure.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/argsUsedOnlyInClosure.test new file mode 100644 index 000000000000..7ff5598dbdff --- /dev/null +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/argsUsedOnlyInClosure.test @@ -0,0 +1,15 @@ +def foo(b, c) { + [].each { + b.plus(c) + } +} +----- +def foo(b, c) { + testMethod(b, c) +} + +private testMethod(b, c) { + [].each { + b.plus(c) + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/output1.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/output1.test index d77f380f9410..e1738a81d52c 100644 --- a/plugins/groovy/testdata/groovy/refactoring/extractMethod/output1.test +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/output1.test @@ -12,7 +12,7 @@ class S { ----- class S { def r() { - Closure sin = testMethod() + Closure sin = testMethod() 10.times { @@ -21,7 +21,7 @@ class S { } - private Closure testMethod() { + private Closure testMethod() { Closure sin = {x -> Math.sin(x)} return sin } diff --git a/plugins/groovy/testdata/highlighting/PrefixIncrementCfa.groovy b/plugins/groovy/testdata/highlighting/PrefixIncrementCfa.groovy index 711bb7b8c062..e886f8664bdf 100644 --- a/plugins/groovy/testdata/highlighting/PrefixIncrementCfa.groovy +++ b/plugins/groovy/testdata/highlighting/PrefixIncrementCfa.groovy @@ -1,7 +1,7 @@ int idx idx = 2 idx = 3 -if (++idx == 8) { //Assignment is used here +if (++idx == 8) { idx = 33 } print idx \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/UnusedInc.groovy b/plugins/groovy/testdata/highlighting/UnusedInc.groovy new file mode 100644 index 000000000000..3483ac2f7b68 --- /dev/null +++ b/plugins/groovy/testdata/highlighting/UnusedInc.groovy @@ -0,0 +1,7 @@ +def a = 4 +print (++a) +print (a++) + +def b = 3 +b++ +b = 3 \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/arithmetic/post1.test b/plugins/groovy/testdata/parsing/groovy/expressions/arithmetic/post1.test index 65d287aed2d6..e51d2abf5bda 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/arithmetic/post1.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/arithmetic/post1.test @@ -3,8 +3,8 @@ Groovy script Unary expression PsiElement(!)('!') - Postfix expression - Postfix expression + Unary expression + Unary expression Literal PsiElement(Integer)('3') PsiElement(++)('++') diff --git a/plugins/groovy/testdata/parsing/groovy/statements/for/for10.test b/plugins/groovy/testdata/parsing/groovy/statements/for/for10.test index 24de169dd13b..bec24b69f0a0 100644 --- a/plugins/groovy/testdata/parsing/groovy/statements/for/for10.test +++ b/plugins/groovy/testdata/parsing/groovy/statements/for/for10.test @@ -31,7 +31,7 @@ Groovy script PsiWhiteSpace(' ') PsiElement(;)(';') PsiWhiteSpace(' ') - Postfix expression + Unary expression Reference expression PsiElement(identifier)('i') PsiElement(++)('++') diff --git a/plugins/groovy/testdata/parsing/groovy/statements/for/for6.test b/plugins/groovy/testdata/parsing/groovy/statements/for/for6.test index 8cea9c0925fb..42f99b3dda73 100644 --- a/plugins/groovy/testdata/parsing/groovy/statements/for/for6.test +++ b/plugins/groovy/testdata/parsing/groovy/statements/for/for6.test @@ -26,7 +26,7 @@ Groovy script PsiElement(Integer)('5') PsiElement(;)(';') PsiWhiteSpace(' ') - Postfix expression + Unary expression Reference expression PsiElement(identifier)('i') PsiElement(++)('++') diff --git a/plugins/groovy/testdata/parsing/groovy/statements/for/for9.test b/plugins/groovy/testdata/parsing/groovy/statements/for/for9.test index 24de169dd13b..bec24b69f0a0 100644 --- a/plugins/groovy/testdata/parsing/groovy/statements/for/for9.test +++ b/plugins/groovy/testdata/parsing/groovy/statements/for/for9.test @@ -31,7 +31,7 @@ Groovy script PsiWhiteSpace(' ') PsiElement(;)(';') PsiWhiteSpace(' ') - Postfix expression + Unary expression Reference expression PsiElement(identifier)('i') PsiElement(++)('++') diff --git a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenPlugin.java b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenPlugin.java index 9f6c8efb1e84..8b9a31793075 100644 --- a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenPlugin.java +++ b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenPlugin.java @@ -18,6 +18,7 @@ package org.jetbrains.idea.maven.model; import com.intellij.openapi.util.JDOMUtil; import org.jdom.Element; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.Serializable; @@ -86,6 +87,17 @@ public class MavenPlugin implements Serializable { return myDependencies; } + @Nullable + public Element getGoalConfiguration(@NotNull String goal) { + for (MavenPlugin.Execution each : getExecutions()) { + if (each.getGoals().contains(goal)) { + return each.getConfigurationElement(); + } + } + + return null; + } + public String getDisplayString() { StringBuilder builder = new StringBuilder(); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/compiler/MavenResourceCompiler.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/compiler/MavenResourceCompiler.java index ca6c14b1ba73..d736683ad70d 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/compiler/MavenResourceCompiler.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/compiler/MavenResourceCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -96,7 +96,7 @@ public class MavenResourceCompiler implements ClassPostProcessingCompiler { } private static Set createPathsSet() { - return new THashSet(FileUtil.T_HASHING_STRATEGY); + return new THashSet(FileUtil.PATH_HASHING_STRATEGY); } private void saveCache(final Project project) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPluginConfigurationDomExtender.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPluginConfigurationDomExtender.java index 44cb3dff60bd..eebd3737476a 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPluginConfigurationDomExtender.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPluginConfigurationDomExtender.java @@ -17,7 +17,9 @@ package org.jetbrains.idea.maven.dom; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.NameUtil; +import com.intellij.psi.xml.XmlElement; import com.intellij.psi.xml.XmlTag; import com.intellij.util.xml.DomElement; import com.intellij.util.xml.GenericDomValue; @@ -34,13 +36,15 @@ import org.jetbrains.idea.maven.dom.converters.MavenPluginCustomParameterValueCo import org.jetbrains.idea.maven.dom.model.MavenDomConfiguration; import org.jetbrains.idea.maven.dom.model.MavenDomConfigurationParameter; import org.jetbrains.idea.maven.dom.model.MavenDomPluginExecution; -import org.jetbrains.idea.maven.dom.model.MavenDomPluginManagement; import org.jetbrains.idea.maven.dom.plugin.MavenDomMojo; import org.jetbrains.idea.maven.dom.plugin.MavenDomParameter; import org.jetbrains.idea.maven.dom.plugin.MavenDomPluginModel; import java.lang.annotation.Annotation; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; public class MavenPluginConfigurationDomExtender extends DomExtender { public static final Key PLUGIN_PARAMETER_KEY = Key.create("MavenPluginConfigurationDomExtender.PLUGIN_PARAMETER_KEY"); @@ -53,21 +57,26 @@ public class MavenPluginConfigurationDomExtender extends DomExtender collectParameters(MavenDomPluginModel pluginModel, MavenDomConfiguration config) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPluginDomUtil.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPluginDomUtil.java index 7cbcfa2e51de..63bcc9862a2b 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPluginDomUtil.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPluginDomUtil.java @@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.xml.DomElement; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.dom.model.MavenDomPlugin; import org.jetbrains.idea.maven.dom.plugin.MavenDomPluginModel; import org.jetbrains.idea.maven.project.MavenProjectsManager; @@ -28,6 +29,7 @@ import org.jetbrains.idea.maven.utils.MavenArtifactUtil; import java.io.File; public class MavenPluginDomUtil { + @Nullable public static MavenDomPluginModel getMavenPluginModel(DomElement element) { Project p = element.getXmlElement().getProject(); @@ -40,6 +42,7 @@ public class MavenPluginDomUtil { return MavenDomUtil.getMavenDomModel(p, pluginXmlFile, MavenDomPluginModel.class); } + @Nullable private static VirtualFile getPluginXmlFile(Project p, MavenDomPlugin pluginElement) { String groupId = pluginElement.getGroupId().getStringValue(); String artifactId = pluginElement.getArtifactId().getStringValue(); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java index 843f8d2caa97..5aa8a7c57fb1 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImporter.java @@ -22,12 +22,14 @@ import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; +import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.model.MavenArtifact; +import org.jetbrains.idea.maven.model.MavenPlugin; import org.jetbrains.idea.maven.project.*; import org.jetbrains.idea.maven.server.MavenEmbedderWrapper; import org.jetbrains.idea.maven.server.NativeMavenProjectHolder; @@ -38,14 +40,31 @@ import java.util.*; public abstract class MavenImporter { public static ExtensionPointName EXTENSION_POINT_NAME = ExtensionPointName.create("org.jetbrains.idea.maven.importer"); - protected final String myPluginGroupID; - protected final String myPluginArtifactID; - public MavenImporter(String pluginGroupID, String pluginArtifactID) { + @Deprecated + protected String myPluginGroupID; + + @Deprecated + protected String myPluginArtifactID; + + private final NullableFunction myPluginFinder; + + public MavenImporter(final String pluginGroupID, final String pluginArtifactID) { + this(new NullableFunction() { + @Override + public MavenPlugin fun(MavenProject mavenProject) { + return mavenProject.findPlugin(pluginGroupID, pluginArtifactID); + } + }); + myPluginGroupID = pluginGroupID; myPluginArtifactID = pluginArtifactID; } + protected MavenImporter(NullableFunction pluginFinder) { + myPluginFinder = pluginFinder; + } + public static List getSuitableImporters(MavenProject p) { final List result = new ArrayList(); final Set moduleTypes = new THashSet(); @@ -81,8 +100,13 @@ public abstract class MavenImporter { }); } + @Nullable + protected MavenPlugin getPlugin(MavenProject mavenProject) { + return myPluginFinder.fun(mavenProject); + } + public boolean isApplicable(MavenProject mavenProject) { - return mavenProject.findPlugin(myPluginGroupID, myPluginArtifactID) != null; + return getPlugin(mavenProject) != null; } @NotNull @@ -136,7 +160,8 @@ public abstract class MavenImporter { @Nullable protected Element getConfig(MavenProject p) { - return p.getPluginConfiguration(myPluginGroupID, myPluginArtifactID); + MavenPlugin plugin = getPlugin(p); + return plugin == null ? null : plugin.getConfigurationElement(); } @Nullable @@ -155,8 +180,9 @@ public abstract class MavenImporter { } @Nullable - protected Element getGoalConfig(MavenProject p, String goal) { - return p.getPluginGoalConfiguration(myPluginGroupID, myPluginArtifactID, goal); + protected Element getGoalConfig(MavenProject p, @NotNull String goal) { + MavenPlugin plugin = getPlugin(p); + return plugin == null ? null : plugin.getGoalConfiguration(goal); } @Nullable diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenArtifactDownloader.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenArtifactDownloader.java index ced430176ea0..0aee05f9e8dc 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenArtifactDownloader.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenArtifactDownloader.java @@ -90,23 +90,8 @@ public class MavenArtifactDownloader { return download(artifacts, downloadedFiles); } finally { - scheduleFilesRefresh(downloadedFiles); - } - } - - private void scheduleFilesRefresh(final List downloadedFiles) { - Runnable refreshTask = new Runnable() { - public void run() { - LocalFileSystem.getInstance().refreshIoFiles(downloadedFiles); - } - }; - - if (ApplicationManager.getApplication().isUnitTestMode() - || ApplicationManager.getApplication().isDispatchThread()) { - refreshTask.run(); - } - else { - ApplicationManager.getApplication().invokeLater(refreshTask); + boolean isAsync = !ApplicationManager.getApplication().isUnitTestMode(); + LocalFileSystem.getInstance().refreshIoFiles(downloadedFiles, isAsync, false, null); } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java index 9487d00d168d..258972e1bb52 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java @@ -29,6 +29,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.SmartList; +import com.intellij.util.containers.CollectionFactory; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashMap; import gnu.trove.THashSet; @@ -617,9 +618,9 @@ public class MavenProject { @NotNull public Set getSupportedPackagings() { - Set result = new THashSet(Arrays.asList(MavenConstants.TYPE_POM, - MavenConstants.TYPE_JAR, - "ejb", "ejb-client", "war", "ear", "bundle")); + Set result = CollectionFactory.newSet(MavenConstants.TYPE_POM, + MavenConstants.TYPE_JAR, + "ejb", "ejb-client", "war", "ear", "bundle", "maven-plugin"); for (MavenImporter each : getSuitableImporters()) { each.getSupportedPackagings(result); } @@ -727,18 +728,11 @@ public class MavenProject { MavenPlugin plugin = findPlugin(groupId, artifactId); if (plugin == null) return null; - Element configElement = null; if (goalOrNull == null) { - configElement = plugin.getConfigurationElement(); + return plugin.getConfigurationElement(); } - else { - for (MavenPlugin.Execution each : plugin.getExecutions()) { - if (each.getGoals().contains(goalOrNull)) { - configElement = each.getConfigurationElement(); - } - } - } - return configElement; + + return plugin.getGoalConfiguration(goalOrNull); } @Nullable diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java index c8d10de2385e..d19ce28b6230 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -58,6 +58,7 @@ import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.idea.maven.utils.MavenLog; import org.jetbrains.idea.maven.utils.MavenProgressIndicator; import org.jetbrains.idea.maven.utils.MavenUtil; +import com.intellij.openapi.util.SystemInfoRt; import java.io.File; import java.nio.charset.Charset; @@ -172,6 +173,7 @@ public class MavenServerManager extends RemoteObjectWrapper { final ArrayList classPath = new ArrayList(); ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(NotNull.class), classPath); ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(StringUtil.class), classPath); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(SystemInfoRt.class), classPath); ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(THashSet.class), classPath); ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(Element.class), classPath); ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(Query.class), classPath); diff --git a/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesFile.java b/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesFile.java index 48c21e52d951..ba9f2a9f7424 100644 --- a/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesFile.java +++ b/plugins/properties/src/com/intellij/lang/properties/xml/XmlPropertiesFile.java @@ -31,6 +31,7 @@ import java.util.*; */ public class XmlPropertiesFile implements PropertiesFile { + private static final Key> KEY = Key.create("xml properties file"); private final XmlFile myFile; private final List myProperties = new ArrayList(); private final MultiMap myPropertiesMap = new MultiMap(); @@ -42,7 +43,7 @@ public class XmlPropertiesFile implements PropertiesFile { public static PropertiesFile getPropertiesFile(final XmlFile file) { CachedValuesManager manager = CachedValuesManager.getManager(file.getProject()); - return manager.getCachedValue(file, Key.>create("xml properties file"), + return manager.getCachedValue(file, KEY, new CachedValueProvider() { @Override public Result compute() { @@ -104,13 +105,13 @@ public class XmlPropertiesFile implements PropertiesFile { @NotNull @Override public PsiElement addProperty(@NotNull IProperty property) throws IncorrectOperationException { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } @NotNull @Override public PsiElement addPropertyAfter(@NotNull Property property, @Nullable Property anchor) throws IncorrectOperationException { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java index 3c3a491233b9..1a4e514a2ca5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java @@ -23,6 +23,7 @@ import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNStatus; import org.tmatesoft.svn.core.wc.SVNStatusType; +import java.io.File; import java.util.HashSet; import java.util.Set; @@ -33,7 +34,7 @@ public class NestedCopiesBuilder implements StatusReceiver { mySet = new HashSet(); } - public void process(final FilePath path, final SVNStatus status, final boolean isInnerCopyRoot) throws SVNException { + public void process(final FilePath path, final SVNStatus status) throws SVNException { if ((path.getVirtualFile() != null) && SvnVcs.svnStatusIs(status, SVNStatusType.STATUS_EXTERNAL)) { final MyPointInfo info = new MyPointInfo(path.getVirtualFile(), null, WorkingCopyFormat.UNKNOWN, NestedCopyType.external); mySet.add(info); @@ -46,9 +47,6 @@ public class NestedCopiesBuilder implements StatusReceiver { return; } else if (status.isSwitched()) { type = NestedCopyType.switched; - } else if (isInnerCopyRoot) { - // will not be changed or modified; can't be switched or external - type = NestedCopyType.inner; } else { return; } @@ -63,6 +61,12 @@ public class NestedCopiesBuilder implements StatusReceiver { public void processUnversioned(final VirtualFile vFile) { } + @Override + public void processCopyRoot(VirtualFile file, SVNURL url, WorkingCopyFormat format) { + final MyPointInfo info = new MyPointInfo(file, url, format, NestedCopyType.inner); + mySet.add(info); + } + static class MyPointInfo { private final VirtualFile myFile; private SVNURL myUrl; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java index afd8a5370231..1cd827424c8e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java @@ -18,12 +18,15 @@ package org.jetbrains.idea.svn; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vfs.VirtualFile; import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNStatus; +import java.io.File; import java.util.EventListener; public interface StatusReceiver extends EventListener { - void process(final FilePath path, final SVNStatus status, final boolean isInnerCopyRoot) throws SVNException; + void process(final FilePath path, final SVNStatus status) throws SVNException; void processIgnored(final VirtualFile vFile); void processUnversioned(final VirtualFile vFile); + void processCopyRoot(VirtualFile file, SVNURL url, WorkingCopyFormat format); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java index 4388ee270827..716c1d503cc8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java @@ -26,10 +26,7 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.actions.AbstractShowPropertiesDiffAction; -import org.tmatesoft.svn.core.SVNErrorCode; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNLock; -import org.tmatesoft.svn.core.SVNNodeKind; +import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb; import org.tmatesoft.svn.core.wc.*; @@ -60,7 +57,7 @@ class SvnChangeProviderContext implements StatusReceiver { myBranchConfigurationManager = SvnBranchConfigurationManager.getInstance(myVcs.getProject()); } - public void process(FilePath path, SVNStatus status, boolean isInnerCopyRoot) throws SVNException { + public void process(FilePath path, SVNStatus status) throws SVNException { processStatusFirstPass(path, status); } @@ -72,6 +69,10 @@ class SvnChangeProviderContext implements StatusReceiver { myChangelistBuilder.processUnversionedFile(vFile); } + @Override + public void processCopyRoot(VirtualFile file, SVNURL url, WorkingCopyFormat format) { + } + public ChangelistBuilder getBuilder() { return myChangelistBuilder; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java index f329bbf30601..3928df4a6009 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java @@ -28,10 +28,7 @@ import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNNodeKind; -import org.tmatesoft.svn.core.wc.ISVNStatusHandler; -import org.tmatesoft.svn.core.wc.SVNRevision; -import org.tmatesoft.svn.core.wc.SVNStatus; -import org.tmatesoft.svn.core.wc.SVNStatusClient; +import org.tmatesoft.svn.core.wc.*; import java.io.File; import java.util.LinkedList; @@ -92,7 +89,7 @@ public class SvnRecursiveStatusWalker { } else { // just file final SVNStatus status = item.getClient().doStatus(ioFile, false, false); - myReceiver.process(path, status, false); + myReceiver.process(path, status); } } } @@ -168,14 +165,24 @@ public class SvnRecursiveStatusWalker { private class MyHandler implements ISVNStatusHandler { private MyItem myCurrentItem; + private boolean myMetCurrentItem; public void setCurrentItem(MyItem currentItem) { myCurrentItem = currentItem; + myMetCurrentItem = false; } public void handleStatus(final SVNStatus status) throws SVNException { myPartner.checkCanceled(); final File ioFile = status.getFile(); + if (! myMetCurrentItem && myCurrentItem.isIsInnerCopyRoot()) { + myMetCurrentItem = true; + final SVNStatus statusInner = SvnUtil.getStatus(SvnVcs.getInstance(myProject), myCurrentItem.getPath().getIOFile()); + if (myCurrentItem.getPath().getVirtualFile() != null || statusInner != null) { + myReceiver.processCopyRoot(myCurrentItem.getPath().getVirtualFile(), statusInner.getURL(), + WorkingCopyFormat.getInstance(statusInner.getWorkingCopyFormat())); + } + } final LocalFileSystem lfs = LocalFileSystem.getInstance(); VirtualFile vFile = lfs.findFileByIoFile(ioFile); if (vFile == null) { @@ -190,7 +197,7 @@ public class SvnRecursiveStatusWalker { } } else { final FilePath path = VcsUtil.getFilePath(ioFile, status.getKind().equals(SVNNodeKind.DIR)); - myReceiver.process(path, status, myCurrentItem.isIsInnerCopyRoot()); + myReceiver.process(path, status); } } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index e05f70a8b0b1..3e25901512c5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -299,13 +299,14 @@ public class SvnVcs extends AbstractVcs { ChangeListManager.getInstance(myProject).setReadOnly(SvnChangeProvider.ourDefaultListName, true); supportOptions = myConfiguration.getSupportOptions(myProject); - if (! supportOptions.changeListsSynchronized()) { + if (!supportOptions.changeListsSynchronized()) { processChangeLists(lists); } } catch (ProcessCanceledException e) { // - } finally { + } + finally { if (supportOptions != null) { supportOptions.upgrade(); } @@ -562,7 +563,7 @@ public class SvnVcs extends AbstractVcs { } else { keep = Boolean.getBoolean(KEEP_CONNECTIONS_KEY); } - myPool = new DefaultSVNRepositoryPool(myConfiguration.getAuthenticationManager(this), null, 60*1000, keep); + myPool = new DefaultSVNRepositoryPool(myConfiguration.getAuthenticationManager(this), myConfiguration.getOptions(myProject), 60*1000, keep); } private ISVNRepositoryPool getPool() { @@ -817,11 +818,16 @@ public class SvnVcs extends AbstractVcs { @Nullable public SVNInfo getInfo(final VirtualFile file) { + final File ioFile = new File(file.getPath()); + return getInfo(ioFile); + } + + public SVNInfo getInfo(File ioFile) { try { SVNWCClient wcClient = createWCClient(); - SVNInfo info = wcClient.doInfo(new File(file.getPath()), SVNRevision.UNDEFINED); + SVNInfo info = wcClient.doInfo(ioFile, SVNRevision.UNDEFINED); if (info == null || info.getRepositoryRootURL() == null) { - info = wcClient.doInfo(new File(file.getPath()), SVNRevision.HEAD); + info = wcClient.doInfo(ioFile, SVNRevision.HEAD); } return info; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java index ffd784799587..c265a4969d3f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java @@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.CheckinProjectPanel; import com.intellij.openapi.vcs.FilePath; @@ -176,17 +177,21 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { return Collections.singletonList(committables); } - final MultiMap result = new MultiMap(); + final MultiMap, File> result = new MultiMap, File>(); for (File committable : committables) { final RootUrlInfo path = mySvnVcs.getSvnFileUrlMapping().getWcRootForFilePath(committable); - result.putValue(path == null ? null : path.getRepositoryUrlUrl(), committable); + if (path == null) { + result.putValue(new Pair(null, null), committable); + } else { + result.putValue(new Pair(path.getRepositoryUrlUrl(), path.getFormat()), committable); + } } if (result.size() == 1) { return Collections.singletonList(committables); } final Collection> result2 = new ArrayList>(); - for (Map.Entry> entry : result.entrySet()) { + for (Map.Entry, Collection> entry : result.entrySet()) { result2.add(entry.getValue()); } return result2; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnFormatWorker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnFormatWorker.java index 972bab503239..2e7acdecdb05 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnFormatWorker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnFormatWorker.java @@ -136,9 +136,9 @@ public class SvnFormatWorker extends Task.Backgroundable { if (! wcInfo.isIsWcRoot()) { path = SvnUtil.getWorkingCopyRoot(path); } - indicator.setText(SvnBundle.message("action.Subversion.cleanup.progress.text", path.getAbsolutePath())); try { if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(myNewFormat)) { + indicator.setText(SvnBundle.message("action.Subversion.cleanup.progress.text", path.getAbsolutePath())); wcClient.doCleanup(path); } indicator.setText(SvnBundle.message("action.change.wcopy.format.task.progress.text", path.getAbsolutePath(), diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browser/MkdirOptionsDialog.form b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browser/MkdirOptionsDialog.form index 7717abaf507b..74d271602149 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browser/MkdirOptionsDialog.form +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browser/MkdirOptionsDialog.form @@ -1,8 +1,9 @@
- + + - + @@ -10,7 +11,6 @@ - @@ -18,8 +18,7 @@ - - + @@ -28,7 +27,6 @@ - @@ -36,8 +34,7 @@ - - + @@ -46,17 +43,15 @@ - - + - + - - + @@ -74,8 +69,7 @@ - - + @@ -83,8 +77,7 @@ - - + diff --git a/plugins/svn4ideaOld/src/org/jetbrains/idea/svn/dialogs/browser/MkdirOptionsDialogOld.form b/plugins/svn4ideaOld/src/org/jetbrains/idea/svn/dialogs/browser/MkdirOptionsDialogOld.form index 4db89de78a79..55c8981b8400 100644 --- a/plugins/svn4ideaOld/src/org/jetbrains/idea/svn/dialogs/browser/MkdirOptionsDialogOld.form +++ b/plugins/svn4ideaOld/src/org/jetbrains/idea/svn/dialogs/browser/MkdirOptionsDialogOld.form @@ -1,8 +1,9 @@ - + + - + @@ -10,7 +11,6 @@ - @@ -18,8 +18,7 @@ - - + @@ -28,7 +27,6 @@ - @@ -36,8 +34,7 @@ - - + @@ -46,17 +43,15 @@ - - + - + - - + @@ -74,8 +69,7 @@ - - + @@ -83,8 +77,7 @@ - - + diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java index ab2bba3438e0..a3b5c5e6ab15 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java @@ -735,6 +735,7 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe ContainerUtil.addAll(issues, tasks); } catch (Exception e) { + LOG.warn("Cannot connect to " + repository, e); myBadRepositories.add(repository); if (forceRequest) { notifyAboutConnectionFailure(repository); diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java index aea7d02606fc..64d5933f982e 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java @@ -30,6 +30,11 @@ public final class TreeNodeDescriptor extends NodeDescriptor { myElement = element; } + public TreeNodeDescriptor(@Nullable NodeDescriptor parentDescriptor, Object element, String name) { + this(parentDescriptor, element); + myName = name; + } + @Override public boolean update() { return false; diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java index b2aa0f8e20a4..3dda7b490b9f 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java @@ -359,6 +359,10 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider return myDesignerCard.isVisible() ? myGlassLayer : myErrorLabel; } + public RadComponent getRootComponent() { + return myRootComponent; + } + public Object[] getTreeRoots() { return myRootComponent == null ? ArrayUtil.EMPTY_OBJECT_ARRAY : new Object[]{myRootComponent}; } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyEditor.java index 224c84f81e13..905b3fc515bc 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyEditor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyEditor.java @@ -29,7 +29,7 @@ public abstract class PropertyEditor { private final EventListenerList myListenerList = new EventListenerList(); @NotNull - public abstract JComponent getComponent(@Nullable RadComponent component, Object value); + public abstract JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value); @Nullable public JComponent getPreferredFocusedComponent(@NotNull JComponent component) { diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java index 61dafdd06cbc..df45e10bf096 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java @@ -821,7 +821,7 @@ public final class PropertyTable extends JBTable implements ComponentSelectionLi @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { try { - JComponent component = myEditor.getComponent(getCurrentComponent(), getValue((Property)value)); + JComponent component = myEditor.getComponent(myDesigner.getRootComponent(), getCurrentComponent(), getValue((Property)value)); if (component instanceof JComboBox) { component.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE); diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/AbstractTextFieldEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/AbstractTextFieldEditor.java index 7e1c5c73b798..68435e5609ee 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/AbstractTextFieldEditor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/AbstractTextFieldEditor.java @@ -41,7 +41,7 @@ public abstract class AbstractTextFieldEditor extends PropertyEditor { @NotNull @Override - public JComponent getComponent(@Nullable RadComponent component, Object value) { + public JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value) { setEditorValue(component, value); myTextField.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0)); return myTextField; diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java index 1e181cc43015..d4ac1d7c9bbb 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java @@ -57,7 +57,7 @@ public class BooleanEditor extends PropertyEditor { } @NotNull - public JComponent getComponent(@Nullable RadComponent component, Object value) { + public JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value) { try { myInsideChange = true; myCheckBox.setBackground(UIUtil.getTableBackground()); diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java index b7480910ed49..61b1bab28c3c 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java @@ -80,7 +80,7 @@ public abstract class DomInvocationHandler" + parameter.getName() + "; method=" + method); + throw new AssertionError("No converter specified: String<->" + parameter.getName() + "; method=" + method + "; place=" + myChildDescription); } return converter; } diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/RemoveAttributeIntentionFix.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/RemoveAttributeIntentionFix.java index 8dfa7660095d..4814d65af145 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/RemoveAttributeIntentionFix.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/RemoveAttributeIntentionFix.java @@ -17,25 +17,24 @@ package com.intellij.codeInsight.daemon.impl.analysis; import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.daemon.XmlErrorMessages; -import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.xml.XmlAttribute; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author Maxim.Mossienko */ -public class RemoveAttributeIntentionFix implements IntentionAction { +public class RemoveAttributeIntentionFix extends LocalQuickFixAndIntentionActionOnPsiElement { private final String myLocalName; - private final XmlAttribute myAttribute; public RemoveAttributeIntentionFix(final String localName, final @NotNull XmlAttribute attribute) { + super(attribute); myLocalName = localName; - myAttribute = attribute; } @NotNull @@ -48,20 +47,22 @@ public class RemoveAttributeIntentionFix implements IntentionAction { return XmlErrorMessages.message("remove.attribute.quickfix.family"); } - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return myAttribute.isValid(); - } - - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + @Override + public void invoke(@NotNull Project project, + @NotNull PsiFile file, + @Nullable("is null when called from inspection") Editor editor, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { if (!CodeInsightUtilBase.prepareFileForWrite(file)) return; - PsiElement next = findNextAttribute(myAttribute); - myAttribute.delete(); + PsiElement next = findNextAttribute((XmlAttribute)startElement); + startElement.delete(); - if (next != null) { + if (next != null && editor != null) { editor.getCaretModel().moveToOffset(next.getTextRange().getStartOffset()); } } + @Nullable private static PsiElement findNextAttribute(final XmlAttribute attribute) { PsiElement nextSibling = attribute.getNextSibling(); while (nextSibling != null) { diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlAutoPopupHandler.java b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlAutoPopupHandler.java index 139ea62d72b4..97cbbcef64c8 100644 --- a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlAutoPopupHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlAutoPopupHandler.java @@ -117,7 +117,10 @@ public class XmlAutoPopupHandler extends TypedHandlerDelegate { Boolean result = isRelevantLanguage.get(); if (result == null) { Language language = element.getLanguage(); - if (element instanceof PsiWhiteSpace) language = element.getParent().getLanguage(); + PsiElement parent = element.getParent(); + if (element instanceof PsiWhiteSpace && parent != null) { + language = parent.getLanguage(); + } result = language instanceof XMLLanguage || isAntFile.booleanValue(); isRelevantLanguage.set(result); } diff --git a/xml/impl/src/com/intellij/xml/index/IndexedRelevantResource.java b/xml/impl/src/com/intellij/xml/index/IndexedRelevantResource.java index 17ba1da98290..075b32d8bdf2 100644 --- a/xml/impl/src/com/intellij/xml/index/IndexedRelevantResource.java +++ b/xml/impl/src/com/intellij/xml/index/IndexedRelevantResource.java @@ -21,7 +21,6 @@ import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.util.Function; import com.intellij.util.NullableFunction; import com.intellij.util.indexing.AdditionalIndexedRootsScope; import com.intellij.util.indexing.FileBasedIndex; @@ -38,22 +37,17 @@ import java.util.List; */ public class IndexedRelevantResource implements Comparable> { - public static final Function,VirtualFile> MAPPING = new Function, VirtualFile>() { - public VirtualFile fun(IndexedRelevantResource resource) { - return resource.getFile(); - } - }; - public static List> getResources(ID indexId, final K key, @Nullable final Module module, - @NotNull Project project) { + @NotNull Project project, + @Nullable final GlobalSearchScope additionalScope) { final ArrayList> resources = new ArrayList>(); final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); FileBasedIndex.getInstance().processValues(indexId, key, null, new FileBasedIndex.ValueProcessor() { public boolean process(VirtualFile file, V value) { - ResourceRelevance relevance = ResourceRelevance.getRelevance(file, module, fileIndex); + ResourceRelevance relevance = ResourceRelevance.getRelevance(file, module, fileIndex, additionalScope); if (relevance != ResourceRelevance.NONE) { resources.add(new IndexedRelevantResource(file, key, value, relevance)); } @@ -69,7 +63,8 @@ public class IndexedRelevantResource implements Compara ArrayList> all = new ArrayList>(); Collection allKeys = FileBasedIndex.getInstance().getAllKeys(indexId, module.getProject()); for (K key : allKeys) { - List> resources = getResources(indexId, key, module, module.getProject()); + List> resources = getResources(indexId, key, module, module.getProject(), + null); if (!resources.isEmpty()) { if (chooser == null) { all.add(resources.get(0)); diff --git a/xml/impl/src/com/intellij/xml/index/ResourceRelevance.java b/xml/impl/src/com/intellij/xml/index/ResourceRelevance.java index 411ebc65af19..834478dd78bd 100644 --- a/xml/impl/src/com/intellij/xml/index/ResourceRelevance.java +++ b/xml/impl/src/com/intellij/xml/index/ResourceRelevance.java @@ -34,14 +34,17 @@ public enum ResourceRelevance { SOURCE, MAPPED; - public static ResourceRelevance getRelevance(VirtualFile resource, @Nullable Module module, ProjectFileIndex fileIndex) { + public static ResourceRelevance getRelevance(VirtualFile resource, + @Nullable Module module, + ProjectFileIndex fileIndex, + @Nullable GlobalSearchScope additionalScope) { boolean inTest = fileIndex.isInTestSourceContent(resource); if (module != null) { GlobalSearchScope scope = module.getModuleRuntimeScope(inTest); Module resourceModule = fileIndex.getModuleForFile(resource); if (resourceModule != null && (resourceModule == module || scope.isSearchInModuleContent(resourceModule)) || - scope.contains(resource)) { + scope.contains(resource) || (additionalScope != null && additionalScope.contains(resource))) { return inTest || fileIndex.isInSource(resource) ? SOURCE : LIBRARY; } } diff --git a/xml/impl/src/com/intellij/xml/index/XmlNamespaceIndex.java b/xml/impl/src/com/intellij/xml/index/XmlNamespaceIndex.java index 071ea9df83b9..51f584c0ead8 100644 --- a/xml/impl/src/com/intellij/xml/index/XmlNamespaceIndex.java +++ b/xml/impl/src/com/intellij/xml/index/XmlNamespaceIndex.java @@ -45,7 +45,8 @@ public class XmlNamespaceIndex extends XmlIndex { } public static List> getResourcesByNamespace(String namespace, final Project project, Module module) { - List> resources = IndexedRelevantResource.getResources(NAME, namespace, module, project); + List> resources = IndexedRelevantResource.getResources(NAME, namespace, module, project, + null); Collections.sort(resources); return resources; } diff --git a/xml/impl/src/com/intellij/xml/util/ColorSampleLookupValue.java b/xml/impl/src/com/intellij/xml/util/ColorSampleLookupValue.java index ea5d0e6a52d8..0f564d2bf0ec 100644 --- a/xml/impl/src/com/intellij/xml/util/ColorSampleLookupValue.java +++ b/xml/impl/src/com/intellij/xml/util/ColorSampleLookupValue.java @@ -460,4 +460,9 @@ public class ColorSampleLookupValue implements LookupValueWithUIHint, DeferredUs } return null; } + + @Override + public String toString() { + return myName == null ? myValue : myValue + " " + myName; + } }