diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index d516d5b2f74e..76ceac6ee380 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -546,9 +546,11 @@ public class BuildManager implements ApplicationComponent{ runCommand(new Runnable() { @Override public void run() { + LOG.info("Cancelling preloaded process for project " + projectPath); Pair, OSProcessHandler> pair = takePreloadedProcess(projectPath); if (pair != null) { final RequestFuture future = pair.first; + LOG.info("Cancelling preloaded process, sessionID=" + future.getRequestID()); myMessageDispatcher.cancelSession(future.getRequestID()); // waiting for preloaded process from project's task queue guarantees no build is started for this project // until this one gracefully exits and closes all its storages @@ -559,6 +561,9 @@ public class BuildManager implements ApplicationComponent{ } }); } + else { + LOG.info("takePreloadedProcess() returned null"); + } } }); } diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java index 59c19f0ad7fe..8bf11a9302e2 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java @@ -75,11 +75,19 @@ class BuildMessageDispatcher extends SimpleChannelInboundHandlerAdapter findExpression(PsiElement element, boolean allowMethodCalls) { PsiElement expression = null; PsiElement parent = element.getParent(); - if (parent instanceof PsiLiteralExpression) { + if (parent instanceof PsiLiteralExpression || parent instanceof PsiLambdaExpression) { element = parent; parent = parent.getParent(); } @@ -95,7 +95,7 @@ public class JavaEditorTextProviderImpl implements EditorTextProvider { } else if (parent instanceof PsiReferenceExpression) { final PsiElement pparent = parent.getParent(); - if (pparent instanceof PsiCallExpression) { + if (parent instanceof PsiMethodReferenceExpression || pparent instanceof PsiCallExpression) { parent = pparent; } else if (pparent instanceof PsiReferenceExpression) { @@ -116,11 +116,19 @@ public class JavaEditorTextProviderImpl implements EditorTextProvider { expression = parent; } } - else if (allowMethodCalls) { - PsiElement e = PsiTreeUtil.getParentOfType(element, PsiVariable.class, PsiExpression.class, PsiMethod.class); - if (e instanceof PsiNewExpression) { - if (((PsiNewExpression)e).getAnonymousClass() == null) { - expression = e; + else { + PsiElement castExpr = PsiTreeUtil.getParentOfType(element, PsiTypeCastExpression.class); + if (castExpr != null) { + if (allowMethodCalls || !DebuggerUtils.hasSideEffects(castExpr)) { + expression = castExpr; + } + } + else if (allowMethodCalls) { + PsiElement e = PsiTreeUtil.getParentOfType(element, PsiVariable.class, PsiExpression.class, PsiMethod.class); + if (e instanceof PsiNewExpression) { + if (((PsiNewExpression)e).getAnonymousClass() == null) { + expression = e; + } } } } diff --git a/java/execution/impl/src/com/intellij/execution/JavaRunConfigurationExtensionManager.java b/java/execution/impl/src/com/intellij/execution/JavaRunConfigurationExtensionManager.java index 556027008efd..9ea8e4058f13 100644 --- a/java/execution/impl/src/com/intellij/execution/JavaRunConfigurationExtensionManager.java +++ b/java/execution/impl/src/com/intellij/execution/JavaRunConfigurationExtensionManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package com.intellij.execution; import com.intellij.execution.configuration.RunConfigurationExtensionsManager; import com.intellij.execution.configurations.RunConfigurationBase; -import com.intellij.execution.configurations.RuntimeConfigurationException; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; @@ -26,7 +25,7 @@ import com.intellij.openapi.diagnostic.Logger; * Date: 10/4/11 */ public class JavaRunConfigurationExtensionManager extends RunConfigurationExtensionsManager { - private static final Logger LOG = Logger.getInstance("#" + RunConfigurationExtension.class.getName()); + private static final Logger LOG = Logger.getInstance(RunConfigurationExtension.class); public JavaRunConfigurationExtensionManager() { super(RunConfigurationExtension.EP_NAME); @@ -36,7 +35,7 @@ public class JavaRunConfigurationExtensionManager extends RunConfigurationExtens return ServiceManager.getService(JavaRunConfigurationExtensionManager.class); } - public static void checkConfigurationIsValid(RunConfigurationBase configuration) throws RuntimeConfigurationException { + public static void checkConfigurationIsValid(RunConfigurationBase configuration) { try { getInstance().validateConfiguration(configuration, false); } diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java index b736d9f0b127..de8bcbb84ae6 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,7 +56,7 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration myEnvs = new LinkedHashMap(); + private final Map myEnvs = new LinkedHashMap(); public boolean PASS_PARENT_ENVS = true; public ApplicationConfiguration(final String name, final Project project, ApplicationConfigurationType applicationConfigurationType) { diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurationType.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurationType.java index fba68e43f396..e6e6a0037cee 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurationType.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfigurationType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,10 +33,9 @@ import javax.swing.*; public class ApplicationConfigurationType implements ConfigurationType { private final ConfigurationFactory myFactory; - - /**reflection*/ public ApplicationConfigurationType() { myFactory = new ConfigurationFactoryEx(this) { + @Override public RunConfiguration createTemplateConfiguration(Project project) { return new ApplicationConfiguration("", project, ApplicationConfigurationType.this); } @@ -48,18 +47,22 @@ public class ApplicationConfigurationType implements ConfigurationType { }; } + @Override public String getDisplayName() { return ExecutionBundle.message("application.configuration.name"); } + @Override public String getConfigurationTypeDescription() { return ExecutionBundle.message("application.configuration.description"); } + @Override public Icon getIcon() { return AllIcons.RunConfigurations.Application; } + @Override public ConfigurationFactory[] getConfigurationFactories() { return new ConfigurationFactory[]{myFactory}; } @@ -87,6 +90,7 @@ public class ApplicationConfigurationType implements ConfigurationType { } + @Override @NotNull @NonNls public String getId() { @@ -97,5 +101,4 @@ public class ApplicationConfigurationType implements ConfigurationType { public static ApplicationConfigurationType getInstance() { return ConfigurationTypeUtil.findConfigurationType(ApplicationConfigurationType.class); } - } diff --git a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java index a2256a79b850..24ada216c0d9 100644 --- a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java +++ b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java @@ -62,9 +62,11 @@ public class DefaultSymbolNavigationContributor implements ChooseByNameContribut GlobalSearchScope scope = includeNonProjectItems ? GlobalSearchScope.allScope(project) : GlobalSearchScope.projectScope(project); PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project); + Condition qualifiedMatcher = getQualifiedNameMatcher(pattern); + List result = new ArrayList(); for (PsiMethod method : cache.getMethodsByName(name, scope)) { - if (!method.isConstructor() && isOpenable(method) && !hasSuperMethod(method, scope)) { + if (!method.isConstructor() && isOpenable(method) && !hasSuperMethod(method, scope, qualifiedMatcher)) { result.add(method); } } @@ -87,13 +89,14 @@ public class DefaultSymbolNavigationContributor implements ChooseByNameContribut return member.getContainingFile().getVirtualFile() != null; } - private static boolean hasSuperMethod(PsiMethod method, GlobalSearchScope scope) { + private static boolean hasSuperMethod(PsiMethod method, GlobalSearchScope scope, Condition qualifiedMatcher) { PsiClass containingClass = method.getContainingClass(); if (containingClass == null) return false; for (PsiMethod candidate : containingClass.findMethodsByName(method.getName(), true)) { if (candidate.getContainingClass() != containingClass && PsiSearchScopeUtil.isInScope(scope, candidate) && + qualifiedMatcher.value(candidate) && PsiSuperMethodImplUtil.isSuperMethodSmart(method, candidate)) { return true; } @@ -118,20 +121,7 @@ public class DefaultSymbolNavigationContributor implements ChooseByNameContribut PsiShortNamesCache cache = PsiShortNamesCache.getInstance(scope.getProject()); String completePattern = parameters.getCompletePattern(); - final Condition qualifiedMatcher; - if (completePattern.contains(".")) { - final MinusculeMatcher matcher = new MinusculeMatcher("*" + StringUtil.replace(completePattern, ".", ".*"), NameUtil.MatchingCaseSensitivity.NONE); - qualifiedMatcher = new Condition() { - @Override - public boolean value(PsiMember member) { - String qualifiedName = PsiUtil.getMemberQualifiedName(member); - return qualifiedName != null && matcher.matches(qualifiedName); - } - }; - } else { - //noinspection unchecked - qualifiedMatcher = Condition.TRUE; - } + final Condition qualifiedMatcher = getQualifiedNameMatcher(completePattern); //noinspection UnusedDeclaration final Set collectedMethods = new THashSet(); @@ -163,13 +153,31 @@ public class DefaultSymbolNavigationContributor implements ChooseByNameContribut Iterator iterator = collectedMethods.iterator(); while(iterator.hasNext()) { PsiMethod method = iterator.next(); - if (!hasSuperMethod(method, scope) && !processor.process(method)) return; + if (!hasSuperMethod(method, scope, qualifiedMatcher) && !processor.process(method)) return; ProgressManager.checkCanceled(); iterator.remove(); } } } + private static Condition getQualifiedNameMatcher(String completePattern) { + final Condition qualifiedMatcher; + if (completePattern.contains(".")) { + final MinusculeMatcher matcher = new MinusculeMatcher("*" + StringUtil.replace(completePattern, ".", ".*"), NameUtil.MatchingCaseSensitivity.NONE); + qualifiedMatcher = new Condition() { + @Override + public boolean value(PsiMember member) { + String qualifiedName = PsiUtil.getMemberQualifiedName(member); + return qualifiedName != null && matcher.matches(qualifiedName); + } + }; + } else { + //noinspection unchecked + qualifiedMatcher = Condition.TRUE; + } + return qualifiedMatcher; + } + private static class MyComparator implements Comparator{ public static final MyComparator INSTANCE = new MyComparator(); diff --git a/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy b/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy index 0a5b65deb372..cbe18110f49a 100644 --- a/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy +++ b/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy @@ -239,6 +239,14 @@ class Intf { assert !(sdkRun in noLibs) } + public void "test super method not matching query qualifier"() { + def base = myFixture.addClass("class Base { void xpaint() {} }").methods[0] + def sub = myFixture.addClass("class Sub extends Base { void xpaint() {} }").methods[0] + + assert getPopupElements(new GotoSymbolModel2(project), 'Ba.xpai', false) == [base] + assert getPopupElements(new GotoSymbolModel2(project), 'Su.xpai', false) == [sub] + } + private List getPopupElements(ChooseByNameModel model, String text, boolean checkboxState = false) { return calcPopupElements(createPopup(model), text, checkboxState) } diff --git a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContributionFactory.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContributionFactory.java index 20ebc29fe148..5745d04bf988 100644 --- a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContributionFactory.java +++ b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/module/CloudModuleBuilderContributionFactory.java @@ -30,7 +30,7 @@ public abstract class CloudModuleBuilderContributionFactory { public static CloudModuleBuilderContributionFactory getInstanceByType(ServerType cloudType) { for (CloudModuleBuilderContributionFactory contribution : EP_NAME.getExtensions()) { - if (contribution.getCloudType() == cloudType) { + if (contribution.getCloudType().equals(cloudType)) { return contribution; } } diff --git a/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java b/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java index e86257d8e36f..8fcd8c52a493 100644 --- a/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.highlighting.HighlightUsagesHandler; import com.intellij.ide.DataManager; import com.intellij.injected.editor.EditorWindow; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; @@ -40,9 +41,11 @@ import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; @@ -119,6 +122,7 @@ public abstract class CodeInsightTestCase extends PsiTestCase { for (int i = 0; i < files.length; i++) { String path = files[i]; final String fullPath = FileUtil.toSystemIndependentName(getTestDataPath() + path); + allowRootAccess(fullPath); VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath); vFiles[i] = vFile; assertNotNull("file " + fullPath + " not found", vFile); @@ -129,8 +133,19 @@ public abstract class CodeInsightTestCase extends PsiTestCase { return configureByFiles(projectFile, vFiles); } + private void allowRootAccess(final String filePath) { + VfsRootAccess.allowRootAccess(filePath); + Disposer.register(myTestRootDisposable, new Disposable() { + @Override + public void dispose() { + VfsRootAccess.disallowRootAccess(filePath); + } + }); + } + protected VirtualFile configureByFile(@NonNls String filePath, @Nullable String projectRoot) throws Exception { String fullPath = getTestDataPath() + filePath; + allowRootAccess(fullPath); final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath.replace(File.separatorChar, '/')); assertNotNull("file " + fullPath + " not found", vFile); @@ -475,6 +490,7 @@ public abstract class CodeInsightTestCase extends PsiTestCase { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); String fullPath = getTestDataPath() + filePath; + allowRootAccess(fullPath); final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath.replace(File.separatorChar, '/')); assertNotNull("Cannot find file " + fullPath, vFile); @@ -549,6 +565,7 @@ public abstract class CodeInsightTestCase extends PsiTestCase { protected VirtualFile getVirtualFile(@NonNls @NotNull String filePath) { String fullPath = getTestDataPath() + filePath; + allowRootAccess(fullPath); final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath.replace(File.separatorChar, '/')); assertNotNull("file " + fullPath + " not found", vFile); diff --git a/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java b/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java index cefceb3977e0..c94b71966ad3 100644 --- a/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java +++ b/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java @@ -205,7 +205,7 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas GenericDebuggerRunnerSettings debuggerRunnerSettings = new GenericDebuggerRunnerSettings(); debuggerRunnerSettings.LOCAL = true; - debuggerRunnerSettings.DEBUG_PORT = "3456"; + debuggerRunnerSettings.setDebugPort("3456"); ExecutionEnvironment environment = new ExecutionEnvironmentBuilder(myProject, DefaultDebugExecutor.getDebugExecutorInstance()) .runnerSettings(debuggerRunnerSettings) diff --git a/platform/core-api/src/com/intellij/openapi/project/Project.java b/platform/core-api/src/com/intellij/openapi/project/Project.java index 0683c9b11fe4..122659950375 100644 --- a/platform/core-api/src/com/intellij/openapi/project/Project.java +++ b/platform/core-api/src/com/intellij/openapi/project/Project.java @@ -23,7 +23,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * Project interface class. + * An object representing IntelliJ project.
+ * + *
  • To get all its modules, use {@link com.intellij.openapi.module.ModuleManager#getModules()}
    + * + *
  • To iterate over all project source files and directories, use {@code com.intellij.openapi.roots.ProjectFileIndex.SERVICE.getInstance(project).iterateContent(iterator)}
    + * + *
  • To get the list of all open projects, use {@link com.intellij.openapi.project.ProjectManager#getOpenProjects()} + * */ public interface Project extends ComponentManager, AreaInstance { @NonNls String DIRECTORY_STORE_FOLDER = ProjectCoreUtil.DIRECTORY_BASED_PROJECT_DIR; diff --git a/platform/core-api/src/com/intellij/psi/util/CachedValue.java b/platform/core-api/src/com/intellij/psi/util/CachedValue.java index 309232baee31..0c3db8dcbb36 100644 --- a/platform/core-api/src/com/intellij/psi/util/CachedValue.java +++ b/platform/core-api/src/com/intellij/psi/util/CachedValue.java @@ -17,12 +17,45 @@ package com.intellij.psi.util; import org.jetbrains.annotations.NotNull; +/** + * A wrapper object that holds a computation ({@link #getValueProvider()}) and caches the result of the computation.

    + * + * The recommended way of creation is to use one of {@link com.intellij.psi.util.CachedValuesManager} methods, e.g. + * {@link com.intellij.psi.util.CachedValuesManager#getCachedValue(com.intellij.psi.PsiElement, CachedValueProvider)} + * + * When {@link #getValue()} is invoked the first time, the computation is run and its result is returned and remembered internally. + * In subsequent invocations, the result will be reused to avoid running the same code again and again.

    + * + * The computation will be re-run in the following circumstances: + *

      + *
    1. Garbage collector collects the result cached internally (it's kept via a {@link java.lang.ref.SoftReference}). + *
    2. IDEA determines that cached value is outdated because some its dependencies are changed. See + * {@link com.intellij.psi.util.CachedValueProvider.Result#getDependencyItems()} + *
    + * + * The implementation is thread-safe but not atomic, i.e. if several threads request the cached value simultaneously, the computation may + * be run concurrently on more than one thread. + * + * @param The type of the computation result. + * + * @see com.intellij.psi.util.CachedValueProvider + * @see com.intellij.psi.util.CachedValuesManager + */ public interface CachedValue { + /** + * @return cached value if it's already computed and not outdated, newly computed value otherwise + */ T getValue(); + /** + * @return the object calculating the value to cache + */ @NotNull CachedValueProvider getValueProvider(); + /** + * @return whether there is a cached result inside this object and it's not outdated + */ boolean hasUpToDateValue(); } diff --git a/platform/core-api/src/com/intellij/psi/util/CachedValueProvider.java b/platform/core-api/src/com/intellij/psi/util/CachedValueProvider.java index 80f1c987010d..0601970ac688 100644 --- a/platform/core-api/src/com/intellij/psi/util/CachedValueProvider.java +++ b/platform/core-api/src/com/intellij/psi/util/CachedValueProvider.java @@ -22,15 +22,31 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; +/** + * A computation (typically an anonymous class) to used in {@link com.intellij.psi.util.CachedValue} to cache some computation result. + * @param the type of the cached value + */ public interface CachedValueProvider { + + /** + * @return result object holding the value to cache and the dependencies indicating when that value will be outdated + */ @Nullable Result compute(); + /** + * The object holding the value to cache and the dependencies indicating when that value will be outdated + * @param the type of the cached value + */ class Result { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.util.CachedValueProvider.Result"); private final T myValue; private final Object[] myDependencyItems; + /** + * Constructor + * @see #getDependencyItems() + */ public Result(@Nullable T value, @NotNull Object... dependencyItems) { myValue = value; myDependencyItems = dependencyItems; @@ -50,19 +66,49 @@ public interface CachedValueProvider { return myValue; } + /** + * Dependency items are used in cached values to remember the state of the environment as it was when the value was computed + * and to compare that to the state of the world when querying {@link CachedValue#getValue()}. The state is remembered as + * a collection of {@code long} values representing some time stamps. When changes occur, these stamps are incremented.

    + * + * Dependencies can be following: + *

      + *
    • Instances of {@link com.intellij.openapi.util.ModificationTracker} returning stamps explicitly + *
    • Constant fields of {@link PsiModificationTracker} class, e.g. {@link com.intellij.psi.util.PsiModificationTracker#MODIFICATION_COUNT} + *
    • {@link com.intellij.psi.PsiElement} or {@link com.intellij.openapi.vfs.VirtualFile} objects. Such cache would be dropped + * on any change in the corresponding file + *
    + * + * @return the dependency items + * @see com.intellij.openapi.util.ModificationTracker + * @see com.intellij.psi.util.PsiModificationTracker + * @see com.intellij.openapi.roots.ProjectRootModificationTracker + */ @NotNull public Object[] getDependencyItems() { return myDependencyItems; } + /** + * Creates a result + * @see #getDependencyItems() + */ public static Result createSingleDependency(@Nullable T value, @NotNull Object dependency) { return create(value, dependency); } + /** + * Creates a result + * @see #getDependencyItems() + */ public static Result create(@Nullable T value, @NotNull Object... dependencies) { return new Result(value, dependencies); } + /** + * Creates a result + * @see #getDependencyItems() + */ public static Result create(@Nullable T value, @NotNull Collection dependencies) { return new Result(value, ArrayUtil.toObjectArray(dependencies)); } diff --git a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java index 4c7c12d79906..3a775dadad05 100644 --- a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java +++ b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java @@ -28,6 +28,15 @@ import org.jetbrains.annotations.NotNull; import java.util.concurrent.ConcurrentMap; +/** + * A service used to create and store {@link com.intellij.psi.util.CachedValue} objects.

    + * + * By default cached values are stored in the user data of associated objects implementing {@link com.intellij.openapi.util.UserDataHolder}. + * + * @see #createCachedValue(CachedValueProvider, boolean) + * @see #getCachedValue(com.intellij.psi.PsiElement, CachedValueProvider) + * @see #getCachedValue(com.intellij.openapi.util.UserDataHolder, CachedValueProvider) + */ public abstract class CachedValuesManager { private static final NotNullLazyKey INSTANCE_KEY = ServiceManager.createLazyKey(CachedValuesManager.class); @@ -36,7 +45,9 @@ public abstract class CachedValuesManager { } /** - * Creates new CachedValue instance with given provider. + * Creates new CachedValue instance with given provider. If the return value is marked as trackable, it's treated as + * yet another dependency and must comply its specification. See {@link com.intellij.psi.util.CachedValueProvider.Result#getDependencyItems()} for + * the details. * * @param provider computes values. * @param trackValue if value tracking required. T should be trackable in this case. @@ -47,6 +58,10 @@ public abstract class CachedValuesManager { @NotNull public abstract ParameterizedCachedValue createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider provider, boolean trackValue); + /** + * Rarely needed because it tracks the return value as a dependency. + * @return a CachedValue like in {@link #createCachedValue(CachedValueProvider, boolean)}, with trackable return value. + */ @NotNull public CachedValue createCachedValue(@NotNull CachedValueProvider provider) { return createCachedValue(provider, true); @@ -93,9 +108,18 @@ public abstract class CachedValuesManager { @NotNull CachedValueProvider provider, boolean trackValue); + /** + * Create a cached value with the given provider and non-tracked return value, store it in the first argument's user data. If it's already stored, reuse it. + * @return The cached value + */ public T getCachedValue(@NotNull D dataHolder, @NotNull CachedValueProvider provider) { return getCachedValue(dataHolder, this.getKeyForClass(provider.getClass()), provider, false); } + + /** + * Create a cached value with the given provider and non-tracked return value, store it in PSI element's user data. If it's already stored, reuse it. + * @return The cached value + */ public static T getCachedValue(@NotNull PsiElement psi, @NotNull CachedValueProvider provider) { CachedValuesManager manager = getManager(psi.getProject()); return manager.getCachedValue(psi, manager.getKeyForClass(provider.getClass()), provider, false); diff --git a/platform/core-api/src/com/intellij/psi/util/PsiModificationTracker.java b/platform/core-api/src/com/intellij/psi/util/PsiModificationTracker.java index 02b555c7e9e8..66a7f695c79a 100644 --- a/platform/core-api/src/com/intellij/psi/util/PsiModificationTracker.java +++ b/platform/core-api/src/com/intellij/psi/util/PsiModificationTracker.java @@ -22,11 +22,37 @@ import com.intellij.openapi.util.ModificationTracker; import com.intellij.util.messages.Topic; import org.jetbrains.annotations.NotNull; +/** + * An interface used to support tracking of common PSI modifications. It has three main usage patterns: + *

      + *
    1. Get a stamp of current PSI state. This stamp is increased when PSI is modified, allowing other subsystems + * to check if PSI has changed since they accessed it last time. This can be used to flush and rebuild various internal caches. + * See {@link #getModificationCount()}, {@link #getJavaStructureModificationCount()}, {@link #getOutOfCodeBlockModificationCount()} + * + *
    2. Make a {@link com.intellij.psi.util.CachedValue} instance dependent on a specific PSI modification tracker. + * To achieve that, one should can one of the constants in this interface as {@link com.intellij.psi.util.CachedValueProvider.Result} + * dependencies. + * See {@link #MODIFICATION_COUNT}, {@link #JAVA_STRUCTURE_MODIFICATION_COUNT}, {@link #OUT_OF_CODE_BLOCK_MODIFICATION_COUNT} + * + *
    3. Subscribe to any PSI change (for example, to drop caches in the listener manually). + * See {@link com.intellij.psi.util.PsiModificationTracker.Listener} + * + *
    + */ public interface PsiModificationTracker extends ModificationTracker { + + /** + * Provides a way to get the instance of {@link com.intellij.psi.util.PsiModificationTracker} corresponding to a given project. + * @see #getInstance(com.intellij.openapi.project.Project) + */ class SERVICE { private SERVICE() { } + /** + * @param project + * @return The instance of {@link com.intellij.psi.util.PsiModificationTracker} corresponding to the given project. + */ public static PsiModificationTracker getInstance(Project project) { return ServiceManager.getService(project, PsiModificationTracker.class); } @@ -34,42 +60,71 @@ public interface PsiModificationTracker extends ModificationTracker { /** * This key can be passed as a dependency in a {@link com.intellij.psi.util.CachedValueProvider}. + * The corresponding {@link com.intellij.psi.util.CachedValue} will then be flushed on every physical PSI change. * @see #getModificationCount() */ Key MODIFICATION_COUNT = Key.create("MODIFICATION_COUNT"); /** * This key can be passed as a dependency in a {@link com.intellij.psi.util.CachedValueProvider}. + * The corresponding {@link com.intellij.psi.util.CachedValue} will then be flushed on every physical PSI change that doesn't happen inside a Java code block. * @see #getOutOfCodeBlockModificationCount() */ Key OUT_OF_CODE_BLOCK_MODIFICATION_COUNT = Key.create("OUT_OF_CODE_BLOCK_MODIFICATION_COUNT"); /** * This key can be passed as a dependency in a {@link com.intellij.psi.util.CachedValueProvider}. + * The corresponding {@link com.intellij.psi.util.CachedValue} will then be flushed on every physical PSI change that can affect Java structure and resolve. * @see #getJavaStructureModificationCount() */ Key JAVA_STRUCTURE_MODIFICATION_COUNT = Key.create("JAVA_STRUCTURE_MODIFICATION_COUNT"); + /** + * A topic to subscribe for all PSI modification count changes. + * @see com.intellij.util.messages.MessageBus + */ Topic TOPIC = new Topic("modification tracker", Listener.class, Topic.BroadcastDirection.TO_PARENT); /** * Tracks any PSI modification. - * @return current counter value. + * @return current counter value. Increased whenever any physical PSI is changed. */ @Override long getModificationCount(); + /** + * @return Same as {@link #getJavaStructureModificationCount()}, but also includes changes in non-Java files, e.g. XML. Rarely needed. + */ long getOutOfCodeBlockModificationCount(); + /** + * @return an object returning {@link #getOutOfCodeBlockModificationCount()} + */ @NotNull ModificationTracker getOutOfCodeBlockModificationTracker(); + /** + * Tracks structural Java modifications, i.e. the ones on class/method/field/file level. Modifications inside method bodies are not tracked. + * Useful to work with resolve caches that only depend on Java structure, and not the method code. + * @return current counter value. Increased whenever any physical PSI in Java structure is changed. + */ long getJavaStructureModificationCount(); + /** + * @return an object returning {@link #getJavaStructureModificationCount()} + */ @NotNull ModificationTracker getJavaStructureModificationTracker(); + /** + * A listener to be notified on any PSI modification count change (which happens on any physical PSI change). + * @see #TOPIC + */ interface Listener { + + /** + * A method invoked on Swing EventDispatchThread each time any physical PSI change is detected + */ void modificationCountChanged(); } } diff --git a/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtensionsManager.java b/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtensionsManager.java index af28f681420b..fc443ffd0385 100644 --- a/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtensionsManager.java +++ b/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtensionsManager.java @@ -11,12 +11,11 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.options.SettingsEditorGroup; import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.StringInterner; -import com.intellij.util.containers.WeakStringInterner; +import gnu.trove.THashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,28 +32,25 @@ public class RunConfigurationExtensionsManager> RUN_EXTENSIONS = Key.create("run.extension.elements"); private static final String EXT_ID_ATTR = "ID"; private static final String EXTENSION_ROOT_ATTR = "EXTENSION"; + protected final ExtensionPointName myExtensionPointName; - private final StringInterner myInterner = new WeakStringInterner(); public RunConfigurationExtensionsManager(ExtensionPointName extensionPointName) { myExtensionPointName = extensionPointName; } - public void readExternal(@NotNull final U configuration, - @NotNull final Element parentNode) throws InvalidDataException { - final List children = parentNode.getChildren(getExtensionRootAttr()); - final Map extensions = ContainerUtil.newHashMap(); + public void readExternal(@NotNull U configuration, @NotNull Element parentNode) throws InvalidDataException { + Map extensions = new THashMap(); for (T extension : getApplicableExtensions(configuration)) { extensions.put(extension.getSerializationId(), extension); } + List children = parentNode.getChildren(getExtensionRootAttr()); // if some of extensions settings weren't found we should just keep it because some plugin with extension // may be turned off boolean found = true; - for (Object o : children) { - final Element element = (Element)o; - final String extensionName = element.getAttributeValue(getIdAttrName()); - final T extension = extensions.remove(extensionName); + for (Element element : children) { + final T extension = extensions.remove(element.getAttributeValue(getIdAttrName())); if (extension != null) { extension.readExternal(configuration, element); } @@ -65,9 +61,7 @@ public class RunConfigurationExtensionsManager copy = new ArrayList(children.size()); for (Element child : children) { - Element clone = child.clone(); - JDOMUtil.internElement(clone, myInterner); - copy.add(clone); + copy.add(child.clone()); } configuration.putCopyableUserData(RUN_EXTENSIONS, copy); } @@ -81,31 +75,30 @@ public class RunConfigurationExtensionsManager map = ContainerUtil.newTreeMap(); final List elements = configuration.getCopyableUserData(RUN_EXTENSIONS); if (elements != null) { - for (Element el : elements) { - map.put(el.getAttributeValue(getIdAttrName()), el.clone()); + for (Element element : elements) { + map.put(element.getAttributeValue(getIdAttrName()), element.clone()); } } for (T extension : getApplicableExtensions(configuration)) { - Element el = new Element(getExtensionRootAttr()); - el.setAttribute(getIdAttrName(), extension.getSerializationId()); + Element element = new Element(getExtensionRootAttr()); + element.setAttribute(getIdAttrName(), extension.getSerializationId()); try { - extension.writeExternal(configuration, el); + extension.writeExternal(configuration, element); } - catch (WriteExternalException e) { + catch (WriteExternalException ignored) { map.remove(extension.getSerializationId()); continue; } - map.put(extension.getSerializationId(), el); + map.put(extension.getSerializationId(), element); } - for (Element val : map.values()) { - parentNode.addContent(val); + for (Element values : map.values()) { + parentNode.addContent(values); } } @@ -160,8 +153,8 @@ public class RunConfigurationExtensionsManager getApplicableExtensions(@NotNull final U configuration) { - final List extensions = new ArrayList(); + protected List getApplicableExtensions(@NotNull U configuration) { + List extensions = new SmartList(); for (T extension : Extensions.getExtensions(myExtensionPointName)) { if (extension.isApplicableFor(configuration)) { extensions.add(extension); @@ -170,8 +163,8 @@ public class RunConfigurationExtensionsManager getEnabledExtensions(@NotNull final U configuration, @Nullable RunnerSettings runnerSettings) { - final List extensions = new ArrayList(); + protected List getEnabledExtensions(@NotNull U configuration, @Nullable RunnerSettings runnerSettings) { + List extensions = new SmartList(); for (T extension : Extensions.getExtensions(myExtensionPointName)) { if (extension.isApplicableFor(configuration) && extension.isEnabledFor(configuration, runnerSettings)) { extensions.add(extension); diff --git a/platform/lang-api/src/com/intellij/execution/configurations/LogFileOptions.java b/platform/lang-api/src/com/intellij/execution/configurations/LogFileOptions.java index 0a4132d83a52..a3f212da4e1e 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/LogFileOptions.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/LogFileOptions.java @@ -18,7 +18,6 @@ package com.intellij.execution.configurations; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.SmartList; import com.intellij.util.containers.SmartHashSet; @@ -204,13 +203,13 @@ public class LogFileOptions implements JDOMExternalizable { try { setCharset(Charset.forName(charsetStr)); } - catch (Exception e) { + catch (Exception ignored) { setCharset(Charset.defaultCharset()); } } @Override - public void writeExternal(Element element) throws WriteExternalException { + public void writeExternal(Element element) { element.setAttribute(PATH, FileUtil.toSystemIndependentName(getPathPattern())); element.setAttribute(CHECKED, String.valueOf(isEnabled())); element.setAttribute(SKIPPED, String.valueOf(isSkipContent())); diff --git a/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java b/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java index 2180f7d24edd..16b4d3a18c9b 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/ModuleBasedConfiguration.java @@ -64,15 +64,6 @@ public abstract class ModuleBasedConfiguration mySerializedAccessorNameTracker = new THashSet(); + private final SkipDefaultValuesSerializationFilters mySerializationFilter = new SkipDefaultValuesSerializationFilters() { + @Override + protected boolean accepts(@NotNull Accessor accessor, @NotNull Object bean, @Nullable Object beanValue) { + if (mySerializedAccessorNameTracker.contains(accessor.getName())) { + return true; + } + return super.accepts(accessor, bean, beanValue); + } + }; + + @Override + public final void readExternal(Element element) { + mySerializedAccessorNameTracker.clear(); + XmlSerializer.deserializeInto(this, element, mySerializedAccessorNameTracker); + } + + @Override + public final void writeExternal(Element element) { + XmlSerializer.serializeInto(this, element, mySerializationFilter); + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java b/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java index 4375e164fed4..fa4630b6124a 100644 --- a/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java +++ b/platform/lang-impl/src/com/intellij/execution/configuration/EnvironmentVariablesComponent.java @@ -102,7 +102,7 @@ public class EnvironmentVariablesComponent extends LabeledComponent envs) { + public static void writeExternal(@NotNull Element element, @NotNull Map envs) { final Element envsElement = new Element(ENVS); for (String envName : envs.keySet()) { final Element envElement = new Element(ENV); diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java index da69c0db290a..59e2ac7622a4 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.java @@ -24,7 +24,8 @@ import com.intellij.openapi.extensions.ExtensionException; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.SmartList; -import com.intellij.util.containers.StringInterner; +import gnu.trove.THashMap; +import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -44,6 +45,18 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C private static final String CONFIGURATION_ELEMENT = "ConfigurationWrapper"; @NonNls private static final String RUNNER_ID = "RunnerId"; + + private static final Comparator RUNNER_COMPARATOR = new Comparator() { + @Override + public int compare(@NotNull Element o1, @NotNull Element o2) { + String attributeValue1 = o1.getAttributeValue(RUNNER_ID); + if (attributeValue1 == null) { + return 1; + } + return StringUtil.compare(attributeValue1, o2.getAttributeValue(RUNNER_ID), false); + } + }; + @NonNls private static final String CONFIGURATION_TYPE_ATTRIBUTE = "type"; @NonNls @@ -57,7 +70,7 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C //@NonNls //public static final String UNIQUE_ID = "id"; @NonNls - protected static final String DUMMY_ELEMENT_NANE = "dummy"; + protected static final String DUMMY_ELEMENT_NAME = "dummy"; @NonNls private static final String TEMPORARY_ATTRIBUTE = "temporary"; @NonNls @@ -65,7 +78,6 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C @NonNls public static final String SINGLETON = "singleton"; - /** for compatibility */ @NonNls private static final String TEMP_CONFIGURATION = "tempConfiguration"; @@ -74,11 +86,13 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C private RunConfiguration myConfiguration; private boolean myIsTemplate; - private final Map myRunnerSettings = new HashMap(); - private List myUnloadedRunnerSettings = null; + private final Map myRunnerSettings = new THashMap(); + private List myUnloadedRunnerSettings; + // to avoid changed files + private final Set myLoadedRunnerSettings = new THashSet(); - private final Map myConfigurationPerRunnerSettings = new HashMap(); - private List myUnloadedConfigurationPerRunnerSettings = null; + private final Map myConfigurationPerRunnerSettings = new THashMap(); + private List myUnloadedConfigurationPerRunnerSettings; private boolean myTemporary; private boolean myEditBeforeRun; @@ -146,6 +160,7 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C @Override public String getUniqueID() { + //noinspection deprecation return myConfiguration.getType().getDisplayName() + "." + myConfiguration.getName() + (myConfiguration instanceof UnknownRunConfiguration ? myConfiguration.getUniqueID() : ""); //if (myID == null) { @@ -220,21 +235,23 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C if (myIsTemplate) { myConfiguration = myManager.getConfigurationTemplate(factory).getConfiguration(); - } else { - final String name = element.getAttributeValue(NAME_ATTR); + } + else { // shouldn't call createConfiguration since it calls StepBeforeRunProviders that // may not be loaded yet. This creates initialization order issue. - myConfiguration = myManager.doCreateConfiguration(name, factory, false); + myConfiguration = myManager.doCreateConfiguration(element.getAttributeValue(NAME_ATTR), factory, false); } myConfiguration.readExternal(element); - List runners = element.getChildren(RUNNER_ELEMENT); - myUnloadedRunnerSettings = null; - StringInterner interner = new StringInterner(); - for (final Element runnerElement : runners) { + if (myUnloadedRunnerSettings != null) { + myUnloadedRunnerSettings.clear(); + } + myLoadedRunnerSettings.clear(); + for (Element runnerElement : element.getChildren(RUNNER_ELEMENT)) { String id = runnerElement.getAttributeValue(RUNNER_ID); ProgramRunner runner = RunnerRegistry.getInstance().findRunnerById(id); if (runner != null) { + myLoadedRunnerSettings.add(id); RunnerSettings settings = createRunnerSettings(runner); if (settings != null) { settings.readExternal(runnerElement); @@ -242,36 +259,38 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C myRunnerSettings.put(runner, settings); } else { - if (myUnloadedRunnerSettings == null) myUnloadedRunnerSettings = new SmartList(); - JDOMUtil.internElement(runnerElement, interner); + if (myUnloadedRunnerSettings == null) { + myUnloadedRunnerSettings = new SmartList(); + } myUnloadedRunnerSettings.add(runnerElement); } } - List configurations = element.getChildren(CONFIGURATION_ELEMENT); myUnloadedConfigurationPerRunnerSettings = null; - for (final Object configuration : configurations) { - Element configurationElement = (Element) configuration; - String id = configurationElement.getAttributeValue(RUNNER_ID); - ProgramRunner runner = RunnerRegistry.getInstance().findRunnerById(id); + for (Iterator iterator = element.getChildren(CONFIGURATION_ELEMENT).iterator(); iterator.hasNext(); ) { + Element configurationElement = iterator.next(); + ProgramRunner runner = RunnerRegistry.getInstance().findRunnerById(configurationElement.getAttributeValue(RUNNER_ID)); if (runner != null) { ConfigurationPerRunnerSettings settings = myConfiguration.createRunnerSettings(new InfoProvider(runner)); if (settings != null) { settings.readExternal(configurationElement); } myConfigurationPerRunnerSettings.put(runner, settings); - } else { - if (myUnloadedConfigurationPerRunnerSettings == null) - myUnloadedConfigurationPerRunnerSettings = new ArrayList(1); + } + else { + if (myUnloadedConfigurationPerRunnerSettings == null) { + myUnloadedConfigurationPerRunnerSettings = new SmartList(); + } + + iterator.remove(); myUnloadedConfigurationPerRunnerSettings.add(configurationElement); } } } @Override - public void writeExternal(final Element element) throws WriteExternalException { + public void writeExternal(Element element) throws WriteExternalException { final ConfigurationFactory factory = myConfiguration.getFactory(); - if (!(myConfiguration instanceof UnknownRunConfiguration)) { element.setAttribute(TEMPLATE_FLAG_ATTRIBUTE, String.valueOf(myIsTemplate)); if (!myIsTemplate) { @@ -284,21 +303,22 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C } //element.setAttribute(UNIQUE_ID, getUniqueID()); - if (isEditBeforeRun()) element.setAttribute(EDIT_BEFORE_RUN, String.valueOf(true)); + if (isEditBeforeRun()) { + element.setAttribute(EDIT_BEFORE_RUN, String.valueOf(true)); + } if (myWasSingletonSpecifiedExplicitly || mySingleton != factory.isConfigurationSingletonByDefault()) { element.setAttribute(SINGLETON, String.valueOf(mySingleton)); } if (myTemporary) { - element.setAttribute(TEMPORARY_ATTRIBUTE, Boolean.toString(myTemporary)); + element.setAttribute(TEMPORARY_ATTRIBUTE, Boolean.toString(true)); } } myConfiguration.writeExternal(element); if (!(myConfiguration instanceof UnknownRunConfiguration)) { - final Comparator runnerComparator = createRunnerComparator(); - writeRunnerSettings(runnerComparator, element); - writeConfigurationPerRunnerSettings(runnerComparator, element); + writeRunnerSettings(RUNNER_COMPARATOR, element); + writeConfigurationPerRunnerSettings(RUNNER_COMPARATOR, element); } } @@ -325,16 +345,23 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C } } - private void writeRunnerSettings(final Comparator runnerComparator, final Element element) throws WriteExternalException { - final ArrayList runnerSettings = new ArrayList(); + private void writeRunnerSettings(@NotNull Comparator runnerComparator, @NotNull Element element) throws WriteExternalException { + List runnerSettings = new SmartList(); for (ProgramRunner runner : myRunnerSettings.keySet()) { RunnerSettings settings = myRunnerSettings.get(runner); + boolean wasLoaded = myLoadedRunnerSettings.contains(runner.getRunnerId()); + if (settings == null && !wasLoaded) { + continue; + } + Element runnerElement = new Element(RUNNER_ELEMENT); if (settings != null) { settings.writeExternal(runnerElement); } - runnerElement.setAttribute(RUNNER_ID, runner.getRunnerId()); - runnerSettings.add(runnerElement); + if (wasLoaded || !JDOMUtil.isEmpty(runnerElement)) { + runnerElement.setAttribute(RUNNER_ID, runner.getRunnerId()); + runnerSettings.add(runnerElement); + } } if (myUnloadedRunnerSettings != null) { for (Element unloadedRunnerSetting : myUnloadedRunnerSettings) { @@ -357,7 +384,7 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C myConfiguration.checkConfiguration(); if (myConfiguration instanceof RunConfigurationBase) { final RunConfigurationBase runConfigurationBase = (RunConfigurationBase) myConfiguration; - Set runners = new HashSet(); + Set runners = new THashSet(); runners.addAll(myRunnerSettings.keySet()); runners.addAll(myConfigurationPerRunnerSettings.keySet()); for (ProgramRunner runner : runners) { @@ -379,24 +406,6 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C return true; } - private static Comparator createRunnerComparator() { - return new Comparator() { - @Override - public int compare(final Element o1, final Element o2) { - final String attributeValue1 = o1.getAttributeValue(RUNNER_ID); - if (attributeValue1 == null) { - return 1; - - } - final String attributeValue2 = o2.getAttributeValue(RUNNER_ID); - if (attributeValue2 == null) { - return -1; - } - return attributeValue1.compareTo(attributeValue2); - } - }; - } - @Override public RunnerSettings getRunnerSettings(@NotNull ProgramRunner runner) { if (!myRunnerSettings.containsKey(runner)) { @@ -405,7 +414,7 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C myRunnerSettings.put(runner, runnerSettings); return runnerSettings; } - catch (AbstractMethodError e) { + catch (AbstractMethodError ignored) { LOG.error("Update failed for: " + myConfiguration.getType().getDisplayName() + ", runner: " + runner.getRunnerId(), new ExtensionException(runner.getClass())); } } @@ -442,7 +451,7 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C RunnerSettings data = createRunnerSettings(runner); myRunnerSettings.put(runner, data); if (data != null) { - Element temp = new Element(DUMMY_ELEMENT_NANE); + Element temp = new Element(DUMMY_ELEMENT_NAME); RunnerSettings templateSettings = template.myRunnerSettings.get(runner); if (templateSettings != null) { templateSettings.writeExternal(temp); @@ -455,7 +464,7 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C ConfigurationPerRunnerSettings data = myConfiguration.createRunnerSettings(new InfoProvider(runner)); myConfigurationPerRunnerSettings.put(runner, data); if (data != null) { - Element temp = new Element(DUMMY_ELEMENT_NANE); + Element temp = new Element(DUMMY_ELEMENT_NAME); ConfigurationPerRunnerSettings templateSettings = template.myConfigurationPerRunnerSettings.get(runner); if (templateSettings != null) { templateSettings.writeExternal(temp); @@ -479,7 +488,7 @@ public class RunnerAndConfigurationSettingsImpl implements JDOMExternalizable, C } @Override - public int compareTo(final Object o) { + public int compareTo(@NotNull final Object o) { if (o instanceof RunnerAndConfigurationSettings) { return getName().compareTo(((RunnerAndConfigurationSettings) o).getName()); } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/AllFileTemplatesConfigurable.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/AllFileTemplatesConfigurable.java index 3ac590e5fb38..668089855d7a 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/AllFileTemplatesConfigurable.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/AllFileTemplatesConfigurable.java @@ -327,7 +327,7 @@ public class AllFileTemplatesConfigurable implements SearchableConfigurable, Con }); myMainPanel = new JPanel(new BorderLayout()); - Splitter splitter = new Splitter(); + Splitter splitter = new Splitter(false, 0.3f); JPanel leftPanel = new JPanel(new BorderLayout()); leftPanel.add(myToolBar, BorderLayout.NORTH); leftPanel.add(myTabbedPane.getComponent(), BorderLayout.CENTER); diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java index 199e6b4b1544..01d65df6952b 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java @@ -42,6 +42,7 @@ import com.intellij.openapi.editor.ex.util.LayeredLexerEditorHighlighter; import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; import com.intellij.openapi.fileTypes.*; +import com.intellij.openapi.fileTypes.ex.FileTypeChooser; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; @@ -316,9 +317,14 @@ public class FileTemplateConfigurable implements Configurable, Configurable.NoSc myTemplate.setText(myTemplateEditor.getDocument().getText()); String name = myNameField.getText(); String extension = myExtensionField.getText(); - if (name.length() == 0 || !isValidFilename(name + "." + extension)) { + String filename = name + "." + extension; + if (name.length() == 0 || !isValidFilename(filename)) { throw new ConfigurationException(IdeBundle.message("error.invalid.template.file.name.or.extension")); } + FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(filename); + if (fileType == UnknownFileType.INSTANCE) { + FileTypeChooser.associateFileType(filename); + } myTemplate.setName(name); myTemplate.setExtension(extension); myTemplate.setReformatCode(myAdjustBox.isSelected()); diff --git a/platform/platform-api/src/com/intellij/execution/configurations/PtyCommandLine.java b/platform/platform-api/src/com/intellij/execution/configurations/PtyCommandLine.java index 2b8cdd2a9884..96acaa5d9fa3 100644 --- a/platform/platform-api/src/com/intellij/execution/configurations/PtyCommandLine.java +++ b/platform/platform-api/src/com/intellij/execution/configurations/PtyCommandLine.java @@ -15,7 +15,6 @@ */ package com.intellij.execution.configurations; -import com.google.common.collect.Maps; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.SystemInfo; import com.intellij.util.ArrayUtil; @@ -24,6 +23,7 @@ import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -54,7 +54,7 @@ public class PtyCommandLine extends GeneralCommandLine { @NotNull public Process startProcessWithPty(@NotNull List commands, boolean console) throws IOException { - Map env = Maps.newHashMap(); + Map env = new HashMap(); setupEnvironment(env); if (isRedirectErrorStream()) { diff --git a/platform/platform-api/src/com/intellij/execution/process/ColoredProcessHandler.java b/platform/platform-api/src/com/intellij/execution/process/ColoredProcessHandler.java index 094883aabb06..b2374a3d23ea 100644 --- a/platform/platform-api/src/com/intellij/execution/process/ColoredProcessHandler.java +++ b/platform/platform-api/src/com/intellij/execution/process/ColoredProcessHandler.java @@ -16,10 +16,10 @@ package com.intellij.execution.process; -import com.google.common.collect.Lists; import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.util.Key; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.nio.charset.Charset; @@ -32,7 +32,7 @@ import java.util.List; public class ColoredProcessHandler extends OSProcessHandler implements AnsiEscapeDecoder.ColoredTextAcceptor { private final AnsiEscapeDecoder myAnsiEscapeDecoder = new AnsiEscapeDecoder(); - private final List myColoredTextListeners = Lists.newArrayList(); + private final List myColoredTextListeners = ContainerUtil.newArrayList(); public ColoredProcessHandler(final GeneralCommandLine commandLine) throws ExecutionException { super(commandLine.createProcess(), commandLine.getCommandLineString(), commandLine.getCharset()); diff --git a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java index aa152326a759..11f17f95a299 100644 --- a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java +++ b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java @@ -22,6 +22,7 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.JBCardLayout; import com.intellij.util.PlatformUtils; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -33,7 +34,8 @@ import java.util.List; public class CustomizeIDEWizardDialog extends DialogWrapper implements ActionListener { private static final String BUTTONS = "BUTTONS"; - private static final String NOBUTTONS = "NOBUTTONS"; + private static final String NO_BUTTONS = "NO_BUTTONS"; + private final JButton mySkipButton = new JButton("Skip All and Set Defaults"); private final JButton myBackButton = new JButton("Back"); private final JButton myNextButton = new JButton("Next"); @@ -68,11 +70,11 @@ public class CustomizeIDEWizardDialog extends DialogWrapper implements ActionLis final CustomizeIDEWizardStepsProvider provider; try { - Class providerClass = (Class)Class.forName(stepsProviderName); - provider = providerClass.newInstance(); + Class providerClass = Class.forName(stepsProviderName); + provider = (CustomizeIDEWizardStepsProvider)providerClass.newInstance(); } catch (Throwable e) { - Main.showMessage("Start Failed", e); + Main.showMessage("Configuration Wizard Failed", e); return; } @@ -148,17 +150,17 @@ public class CustomizeIDEWizardDialog extends DialogWrapper implements ActionLis buttonPanel.add(myNextButton, gbc); buttonPanel.setBorder(BorderFactory.createEmptyBorder(8, 0, 0, 0)); myButtonWrapper.add(buttonPanel, BUTTONS); - myButtonWrapper.add(new JLabel(), NOBUTTONS); + myButtonWrapper.add(new JLabel(), NO_BUTTONS); myButtonWrapperLayout.show(myButtonWrapper, BUTTONS); return myButtonWrapper; } void setButtonsVisible(boolean visible) { - myButtonWrapperLayout.show(myButtonWrapper, visible ? BUTTONS : NOBUTTONS); + myButtonWrapperLayout.show(myButtonWrapper, visible ? BUTTONS : NO_BUTTONS); } @Override - public void actionPerformed(ActionEvent e) { + public void actionPerformed(@NotNull ActionEvent e) { if (e.getSource() == mySkipButton) { doOKAction(); return; diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java index fdf11dc54e4d..155389da46bf 100644 --- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java +++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java @@ -15,10 +15,14 @@ */ package com.intellij.idea; +import com.intellij.ide.customize.CustomizeIDEWizardDialog; +import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.ide.startupWizard.StartupWizard; import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.application.ConfigImportHelper; import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.application.ex.ApplicationInfoEx; import com.intellij.openapi.application.impl.ApplicationInfoImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.SystemInfo; @@ -30,6 +34,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.AppUIUtil; import com.intellij.util.Consumer; import com.intellij.util.EnvironmentUtil; +import com.intellij.util.PlatformUtils; import com.intellij.util.lang.UrlClassLoader; import com.sun.jna.Native; import org.jetbrains.annotations.NonNls; @@ -66,14 +71,14 @@ public class StartupUtil { ourLock.setActivateListener(consumer); } - interface AppStarter { - void start(boolean newConfigFolder); - } - public synchronized static int getAcquiredPort() { return ourLock.getAcquiredPort(); } + interface AppStarter { + void start(boolean newConfigFolder); + } + static void prepareAndStart(String[] args, AppStarter appStarter) { boolean newConfigFolder = false; @@ -294,4 +299,29 @@ public class StartupUtil { log.info("JVM Args: " + StringUtil.join(arguments, " ")); } } + + static void runStartupWizard() { + ApplicationInfoEx appInfo = ApplicationInfoImpl.getShadowInstance(); + + String stepsProvider = appInfo.getCustomizeIDEWizardStepsProvider(); + if (stepsProvider != null) { + CustomizeIDEWizardDialog.showCustomSteps(stepsProvider); + PluginManagerCore.invalidatePlugins(); + return; + } + + if (PlatformUtils.isIntelliJ()) { + new CustomizeIDEWizardDialog().show(); + PluginManagerCore.invalidatePlugins(); + return; + } + + List pages = appInfo.getPluginChooserPages(); + if (!pages.isEmpty()) { + StartupWizard startupWizard = new StartupWizard(pages); + startupWizard.setCancelText("Skip"); + startupWizard.show(); + PluginManagerCore.invalidatePlugins(); + } + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/AbstractFileType.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/AbstractFileType.java index 7b43dfdff4f3..de74d6760915 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/AbstractFileType.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/AbstractFileType.java @@ -26,6 +26,7 @@ import com.intellij.openapi.options.ExternalInfo; import com.intellij.openapi.options.ExternalizableScheme; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.util.*; +import com.intellij.util.ArrayUtil; import com.intellij.util.text.StringTokenizer; import org.jdom.Element; import org.jdom.output.XMLOutputter; @@ -279,12 +280,12 @@ public class AbstractFileType extends UserFileType implements private static Element writeKeywords(Set keywords, String tagName, Element highlightingElement) { if (keywords.size() == 0 && !ELEMENT_KEYWORDS.equals(tagName)) return null; Element keywordsElement = new Element(tagName); - String[] strings = keywords.toArray(new String[keywords.size()]); + String[] strings = ArrayUtil.toStringArray(keywords); Arrays.sort(strings); StringBuilder keywordsAttribute = new StringBuilder(); for (final String keyword : strings) { - if (keyword.indexOf(SEMICOLON) == -1) { + if (!keyword.contains(SEMICOLON)) { if (keywordsAttribute.length() != 0) keywordsAttribute.append(SEMICOLON); keywordsAttribute.append(keyword); } else { diff --git a/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.java b/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.java index d9ebeefa7acc..a3e5e199a9ec 100644 --- a/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.java +++ b/platform/platform-impl/src/com/intellij/ui/AbstractExpandableItemsHandler.java @@ -19,8 +19,8 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.registry.Registry; -import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.popup.AbstractPopup; +import com.intellij.ui.popup.OurHeavyWeightPopup; import com.intellij.util.Alarm; import com.intellij.util.JBHiDPIScaledImage; import com.intellij.util.ui.UIUtil; @@ -42,7 +42,7 @@ public abstract class AbstractExpandableItemsHandler implements @Override public void succeeded() { synchronized (myRemoteDeployments) { + for (DeploymentImpl deployment : new ArrayList(myDeployments)) { + DeploymentImpl oldDeployment = myRemoteDeployments.get(deployment.getName()); + if (oldDeployment != null) { + oldDeployment.changeState(oldDeployment.getStatus(), + deployment.getStatus(), deployment.getStatusText(), deployment.getRuntime()); + myDeployments.remove(deployment); + myDeployments.add(oldDeployment); + } + } myRemoteDeployments.clear(); for (DeploymentImpl deployment : myDeployments) { myRemoteDeployments.put(deployment.getName(), deployment); diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/log/LoggingHandlerImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/log/LoggingHandlerImpl.java index 7434b10c453e..0637a2f43bb7 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/log/LoggingHandlerImpl.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/log/LoggingHandlerImpl.java @@ -7,6 +7,7 @@ import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.remoteServer.runtime.log.LoggingHandler; import org.jetbrains.annotations.NotNull; @@ -18,6 +19,7 @@ public class LoggingHandlerImpl implements LoggingHandler { public LoggingHandlerImpl(@NotNull Project project) { myConsole = TextConsoleBuilderFactory.getInstance().createBuilder(project).getConsole(); + Disposer.register(project, myConsole); } @NotNull diff --git a/platform/util/src/com/intellij/openapi/util/UserDataHolder.java b/platform/util/src/com/intellij/openapi/util/UserDataHolder.java index 95879f771f73..9c88bcadcfc2 100644 --- a/platform/util/src/com/intellij/openapi/util/UserDataHolder.java +++ b/platform/util/src/com/intellij/openapi/util/UserDataHolder.java @@ -18,8 +18,18 @@ package com.intellij.openapi.util; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.NotNull; +/** + * Allows to store custom user data within a model object. This might be preferred to an explicit Map with model objects as keys and + * custom data in values because this allows the data to be garbage-collected together with the values. + */ public interface UserDataHolder { + /** + * @return a user data value associated with this object. Doesn't require read action. + */ @Nullable T getUserData(@NotNull Key key); + /** + * Add a new user data value to this object. Doesn't require write action. + */ void putUserData(@NotNull Key key, @Nullable T value); } \ No newline at end of file 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 ba8554c08e28..9f2f837f6332 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -1827,7 +1827,7 @@ public class StringUtil extends StringUtilRt { @Contract(pure = true) public static int indexOf(@NotNull CharSequence sequence, @NotNull CharSequence infix) { - for (int i = 0; i < sequence.length() - infix.length(); i++) { + for (int i = 0; i <= sequence.length() - infix.length(); i++) { if (startsWith(sequence, i, infix)) { return i; } diff --git a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java index 28d23331d090..c9078e63b009 100644 --- a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java @@ -100,11 +100,12 @@ class BeanBinding implements Binding { } } + if (element == null) { + element = new Element(myTagName); + } + Object node = binding.serialize(o, element, filter); if (node != null) { - if (element == null) { - element = new Element(myTagName); - } if (node instanceof org.jdom.Attribute) { element.setAttribute((org.jdom.Attribute)node); } @@ -129,10 +130,12 @@ class BeanBinding implements Binding { if (element == null) { return o; } - return deserializeInto(XmlSerializerImpl.newInstance(myBeanClass), element); + Object instance = XmlSerializerImpl.newInstance(myBeanClass); + deserializeInto(instance, element, null); + return instance; } - public Object deserializeInto(@NotNull Object result, @NotNull Element element) { + public void deserializeInto(@NotNull Object result, @NotNull Element element, @Nullable Set accessorNameTracker) { Set bindings = myPropertyBindings.keySet(); MultiMap data = MultiMap.createSmartList(); nextNode: @@ -155,10 +158,11 @@ class BeanBinding implements Binding { } for (Binding binding : data.keySet()) { + if (accessorNameTracker != null) { + accessorNameTracker.add(myPropertyBindings.get(binding).getName()); + } binding.deserialize(result, ArrayUtil.toObjectArray(data.get(binding))); } - - return result; } @Override diff --git a/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java b/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java index 7dd7f6856cae..76fa9d08c0e1 100644 --- a/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java +++ b/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java @@ -26,6 +26,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.lang.reflect.Array; import java.net.URL; +import java.util.Set; public class XmlSerializer { private static final SerializationFilter TRUE_FILTER = new SerializationFilter() { @@ -101,8 +102,12 @@ public class XmlSerializer { } public static void deserializeInto(@NotNull Object bean, @NotNull Element element) { + deserializeInto(bean, element, null); + } + + public static void deserializeInto(@NotNull Object bean, @NotNull Element element, @Nullable Set accessorNameTracker) { try { - ((BeanBinding)XmlSerializerImpl.getBinding(bean.getClass())).deserializeInto(bean, element); + ((BeanBinding)XmlSerializerImpl.getBinding(bean.getClass())).deserializeInto(bean, element, accessorNameTracker); } catch (XmlSerializationException e) { throw e; diff --git a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java index 8b11f1f33db6..495c38fcd1c2 100644 --- a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java +++ b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java @@ -281,4 +281,11 @@ public class StringUtilTest extends TestCase { assertFalse(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("xyx"), StringUtil.stringHashCodeIgnoreWhitespaces("xxx"))); assertFalse(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("xyx"), StringUtil.stringHashCodeIgnoreWhitespaces("xYx"))); } + + public void testContains() { + assertTrue(StringUtil.contains("1", "1")); + assertFalse(StringUtil.contains("1", "12")); + assertTrue(StringUtil.contains("12", "1")); + assertTrue(StringUtil.contains("12", "2")); + } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/statistics/VcsLogRepoSizeCollector.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/statistics/VcsLogRepoSizeCollector.java index d9ebf0cee2dc..9b4c856bb7dc 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/statistics/VcsLogRepoSizeCollector.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/statistics/VcsLogRepoSizeCollector.java @@ -17,12 +17,14 @@ package com.intellij.vcs.log.statistics; import com.intellij.internal.statistic.AbstractApplicationUsagesCollector; import com.intellij.internal.statistic.CollectUsagesException; +import com.intellij.internal.statistic.beans.ConvertUsagesUtil; import com.intellij.internal.statistic.beans.GroupDescriptor; import com.intellij.internal.statistic.beans.UsageDescriptor; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.VcsKey; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; import com.intellij.vcs.log.VcsLogProvider; import com.intellij.vcs.log.graph.PermanentGraph; import com.intellij.vcs.log.impl.VcsLogContentProvider; @@ -46,12 +48,12 @@ public class VcsLogRepoSizeCollector extends AbstractApplicationUsagesCollector VcsLogUiImpl ui = logManager.getLogUi(); if (ui != null) { PermanentGraph permanentGraph = ui.getDataPack().getPermanentGraph(); - Map rootCounts = groupRootsByVcs(ui.getDataPack().getLogProviders()); + MultiMap groupedRoots = groupRootsByVcs(ui.getDataPack().getLogProviders()); Set usages = ContainerUtil.newHashSet(); usages.add(new UsageDescriptor("vcs.log.commit.count", permanentGraph.getAllCommits().size())); - for (Map.Entry entry : rootCounts.entrySet()) { - usages.add(new RootUsage(entry.getKey(), entry.getValue())); + for (VcsKey vcs : groupedRoots.keySet()) { + usages.add(new RootUsage(vcs, groupedRoots.get(vcs).size())); } return usages; } @@ -60,18 +62,12 @@ public class VcsLogRepoSizeCollector extends AbstractApplicationUsagesCollector } @NotNull - private static Map groupRootsByVcs(@NotNull Map providers) { - Map result = ContainerUtil.newHashMap(); + private static MultiMap groupRootsByVcs(@NotNull Map providers) { + MultiMap result = MultiMap.create(); for (Map.Entry entry : providers.entrySet()) { - VcsLogProvider provider = entry.getValue(); - VcsKey vcs = provider.getSupportedVcs(); - Integer count = result.get(vcs); - if (count == null) { - result.put(vcs, 1); - } - else { - result.put(vcs, count + 1); - } + VirtualFile root = entry.getKey(); + VcsKey vcs = entry.getValue().getSupportedVcs(); + result.putValue(vcs, root); } return result; } @@ -85,7 +81,7 @@ public class VcsLogRepoSizeCollector extends AbstractApplicationUsagesCollector @SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale") private static class RootUsage extends UsageDescriptor { RootUsage(VcsKey vcs, int value) { - super("vcs.log." + vcs.getName().toLowerCase() + ".root.count", value); + super(ConvertUsagesUtil.ensureProperKey("vcs.log." + vcs.getName().toLowerCase() + ".root.count"), value); } } diff --git a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index 50c45c80bbc6..28e88f5dd3f2 100644 --- a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -577,6 +577,7 @@ twitter typedef typedefs typeof +ubuntu unary unboxing unbuffered