diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java index 3e963fa4177b..b15052fd3d24 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java @@ -167,7 +167,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { } if (enclosingContext instanceof PsiMethod && methodName.equals(enclosingContext.getName()) && - PsiTreeUtil.isAncestor(targetClass, parentClass, true)) { + PsiTreeUtil.isAncestor(targetClass, parentClass, true) && !ref.isQualified()) { FieldConflictsResolver.qualifyReference(ref, method, null); } diff --git a/java/java-psi-impl/src/com/intellij/core/CoreJavaDirectoryService.java b/java/java-psi-impl/src/com/intellij/core/CoreJavaDirectoryService.java index b07f20df3b5a..0c5c1ee2ac2e 100644 --- a/java/java-psi-impl/src/com/intellij/core/CoreJavaDirectoryService.java +++ b/java/java-psi-impl/src/com/intellij/core/CoreJavaDirectoryService.java @@ -18,6 +18,7 @@ package com.intellij.core; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.roots.FileIndexFacade; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.compiled.ClsFileImpl; @@ -44,7 +45,9 @@ public class CoreJavaDirectoryService extends JavaDirectoryService { public PsiClass[] getClasses(@NotNull PsiDirectory dir) { LOG.assertTrue(dir.isValid()); - boolean onlyCompiled = FileIndexFacade.getInstance(dir.getProject()).isInLibraryClasses(dir.getVirtualFile()); + FileIndexFacade index = FileIndexFacade.getInstance(dir.getProject()); + VirtualFile virtualDir = dir.getVirtualFile(); + boolean onlyCompiled = index.isInLibraryClasses(virtualDir) && !index.isInSourceContent(virtualDir); List classes = null; for (PsiFile file : dir.getFiles()) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createMethodFromUsage/afterNoQualification.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createMethodFromUsage/afterNoQualification.java new file mode 100644 index 000000000000..0f3e698ad712 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createMethodFromUsage/afterNoQualification.java @@ -0,0 +1,20 @@ +// "Create Method 'run'" "true" +class Bug { + + interface Foo { + void run(X x); + } + + public static void main(String[] args) { + new Foo() { + @Override + public void run(Bug o) { + o.run(); + } + }; + } + + private void run() { + //To change body of created methods use File | Settings | File Templates. + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createMethodFromUsage/beforeNoQualification.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createMethodFromUsage/beforeNoQualification.java new file mode 100644 index 000000000000..e5407e52e3c5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createMethodFromUsage/beforeNoQualification.java @@ -0,0 +1,16 @@ +// "Create Method 'run'" "true" +class Bug { + + interface Foo { + void run(X x); + } + + public static void main(String[] args) { + new Foo() { + @Override + public void run(Bug o) { + o.run(); + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/psi/resolve/class/ModuleSourceAsLibraryClasses.java b/java/java-tests/testData/psi/resolve/class/ModuleSourceAsLibraryClasses.java new file mode 100644 index 000000000000..8c379ae4ef97 --- /dev/null +++ b/java/java-tests/testData/psi/resolve/class/ModuleSourceAsLibraryClasses.java @@ -0,0 +1,3 @@ +public class ModuleSourceAsLibraryClasses { + ModuleSourceAsLibraryClassesDep field; +} diff --git a/java/java-tests/testData/psi/resolve/class/ModuleSourceAsLibraryClassesDep.java b/java/java-tests/testData/psi/resolve/class/ModuleSourceAsLibraryClassesDep.java new file mode 100644 index 000000000000..bf6b0cacb16c --- /dev/null +++ b/java/java-tests/testData/psi/resolve/class/ModuleSourceAsLibraryClassesDep.java @@ -0,0 +1,16 @@ +/* + * 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. + */ +public class ModuleSourceAsLibraryClassesDep {} diff --git a/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java b/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java index a71da6b32ee6..4c925fe931b2 100644 --- a/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java @@ -23,6 +23,7 @@ import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.packageDependencies.DependenciesBuilder; import com.intellij.psi.*; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.PsiTestUtil; @@ -181,6 +182,23 @@ public class ResolveClassTest extends ResolveTestCase { assertInstanceOf(ref.resolve(), PsiClass.class); } + public void testModuleSourceAsLibraryClasses() throws Exception { + final PsiReference ref = configure(); + PsiFile psiFile = ref.getElement().getContainingFile(); + final VirtualFile file = psiFile.getVirtualFile(); + assertNotNull(file); + createFile(myModule, file.getParent(), "ModuleSourceAsLibraryClassesDep.java", loadFile("class/ModuleSourceAsLibraryClassesDep.java")); + ModuleRootModificationUtil.addModuleLibrary(myModule, "lib", Collections.singletonList(file.getParent().getUrl()), Collections.emptyList()); + //need this to ensure that PsiJavaFileBaseImpl.myResolveCache is filled to reproduce IDEA-91309 + DependenciesBuilder.analyzeFileDependencies(psiFile, new DependenciesBuilder.DependencyProcessor() { + @Override + public void process(PsiElement place, PsiElement dependency) { + } + }); + assertInstanceOf(ref.resolve(), PsiClass.class); + } + + public void testStaticImportInTheSameClass() throws Exception { PsiReference ref = configure(); long start = System.currentTimeMillis(); 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 559d2da1486a..adb7d1980af5 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 @@ -372,7 +372,8 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { assertBounds(srcStart, srcEnd); ProperTextRange srcRange = new ProperTextRange(srcStart, srcEnd); if (dstOffset == srcEnd) return; - assert !srcRange.containsOffset(dstOffset); + assert !srcRange.containsOffset(dstOffset) : + String.format("Can't perform text move from range [%d; %d) to offset %d", srcStart, srcEnd, dstOffset); //CharSequence replacement = getCharsSequence().subSequence(srcStart, srcEnd); String replacement = getCharsSequence().subSequence(srcStart, srcEnd).toString(); diff --git a/platform/lang-impl/src/com/intellij/ide/todo/TodoPanel.java b/platform/lang-impl/src/com/intellij/ide/todo/TodoPanel.java index 6d4a45afb819..0cecf8cb78a6 100644 --- a/platform/lang-impl/src/com/intellij/ide/todo/TodoPanel.java +++ b/platform/lang-impl/src/com/intellij/ide/todo/TodoPanel.java @@ -32,6 +32,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.ui.Splitter; @@ -417,7 +418,11 @@ abstract class TodoPanel extends SimpleToolWindowPanel implements OccurenceNavig public void run() { ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { - myTodoTreeBuilder.rebuildCache(); + try { + myTodoTreeBuilder.rebuildCache(); + } + catch (IndexNotReadyException ignore) { + } } }); final Runnable runnable = new Runnable() { diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java index 3023e42590e4..2b6178bb0eca 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java @@ -322,15 +322,12 @@ public class ArrangementEngine { previous = wrapper; } Changer changer; - // TODO den remove - changer = new NormalChanger(); - // TODO den uncomment - //if (document instanceof DocumentEx) { - // changer = new RangeMarkerAwareChanger((DocumentEx)document); - //} - //else { - // changer = new NormalChanger(); - //} + if (document instanceof DocumentEx) { + changer = new RangeMarkerAwareChanger((DocumentEx)document); + } + else { + changer = new DefaultChanger(); + } return new Context(rearranger, wrappers, document, rules, settings, changer); } } @@ -365,7 +362,7 @@ public class ArrangementEngine { @NotNull Context context); } - private static class NormalChanger implements Changer { + private static class DefaultChanger implements Changer { @NotNull private String myParentText; private int myParentShift; @@ -463,7 +460,7 @@ public class ArrangementEngine { private static class RangeMarkerAwareChanger implements Changer { - @NotNull private final Set> myNotMoved = new HashSet>(); + @NotNull private final List> myWrappers = new ArrayList>(); @NotNull private final DocumentEx myDocument; RangeMarkerAwareChanger(@NotNull DocumentEx document) { @@ -472,8 +469,8 @@ public class ArrangementEngine { @Override public void prepare(@NotNull List> toArrange, @NotNull Context context) { - myNotMoved.clear(); - myNotMoved.addAll(toArrange); + myWrappers.clear(); + myWrappers.addAll(toArrange); for (ArrangementEntryWrapper wrapper : toArrange) { wrapper.updateBlankLines(myDocument); } @@ -503,28 +500,32 @@ public class ArrangementEngine { if (oldWrapper.getStartOffset() > newWrapper.getStartOffset()) { insertionOffset -= newWrapper.getEndOffset() - newWrapper.getStartOffset(); } - myDocument.moveText(newWrapper.getStartOffset(), newWrapper.getEndOffset(), oldWrapper.getStartOffset()); - newWrapper.placeBefore(oldWrapper); - myNotMoved.remove(newWrapper); - for (ArrangementEntryWrapper w : myNotMoved) { - if (w.getStartOffset() >= oldWrapper.getStartOffset() && w.getStartOffset() < newWrapper.getStartOffset()) { - w.applyShift(newWrapper.getEndOffset() - newWrapper.getStartOffset()); - } - else if (w.getStartOffset() < oldWrapper.getStartOffset() && w.getStartOffset() > newWrapper.getStartOffset()) { - w.applyShift(newWrapper.getStartOffset() - newWrapper.getEndOffset()); + if (newWrapper.getStartOffset() != oldWrapper.getStartOffset() || !newWrapper.equals(oldWrapper)) { + myDocument.moveText(newWrapper.getStartOffset(), newWrapper.getEndOffset(), oldWrapper.getStartOffset()); + for (int i = myWrappers.size() - 1; i >= 0; i--) { + ArrangementEntryWrapper w = myWrappers.get(i); + if (w == newWrapper) { + continue; + } + if (w.getStartOffset() >= oldWrapper.getStartOffset() && w.getStartOffset() < newWrapper.getStartOffset()) { + w.applyShift(newWrapper.getEndOffset() - newWrapper.getStartOffset()); + } + else if (w.getStartOffset() < oldWrapper.getStartOffset() && w.getStartOffset() > newWrapper.getStartOffset()) { + w.applyShift(newWrapper.getStartOffset() - newWrapper.getEndOffset()); + } } } if (desiredBlankLinesNumber >= 0 && lineFeedsDiff > 0) { myDocument.insertString(insertionOffset, StringUtil.repeat("\n", lineFeedsDiff)); - shiftOffsets(newWrapper, null, lineFeedsDiff); + shiftOffsets(lineFeedsDiff, insertionOffset); } if (desiredBlankLinesNumber >= 0 && lineFeedsDiff < 0) { // Cut exceeding blank lines. int replacementStartOffset = getBlankLineOffset(-lineFeedsDiff, insertionOffset); myDocument.deleteString(replacementStartOffset, insertionOffset); - shiftOffsets(oldWrapper, null, lineFeedsDiff); + shiftOffsets(replacementStartOffset - insertionOffset, insertionOffset); } // Update wrapper ranges. @@ -556,17 +557,18 @@ public class ArrangementEngine { CharSequence text = myDocument.getCharsSequence(); for (int i = myDocument.getLineStartOffset(startLine - 1) - 1; i >= 0; i = CharArrayUtil.lastIndexOf(text, "\n", i - 1)) { if (--blankLinesNumber <= 0) { - return i; + return i + 1; } } return 0; } - private static void shiftOffsets(@Nullable ArrangementEntryWrapper first, @Nullable ArrangementEntryWrapper last, int shift) { - if (first == null) { - return; - } - for (ArrangementEntryWrapper wrapper = first; wrapper != null && wrapper != last; wrapper = wrapper.getNext()) { + private void shiftOffsets(int shift, int changeOffset) { + for (int i = myWrappers.size() - 1; i >= 0; i--) { + ArrangementEntryWrapper wrapper = myWrappers.get(i); + if (wrapper.getStartOffset() < changeOffset) { + break; + } wrapper.applyShift(shift); } } diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEntryWrapper.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEntryWrapper.java index ffa269459054..a801774f5def 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEntryWrapper.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEntryWrapper.java @@ -113,21 +113,6 @@ public class ArrangementEntryWrapper { return myNext; } - public void placeBefore(@NotNull ArrangementEntryWrapper anchor) { - if (myNext != null) { - myNext.setPrevious(myPrevious); - } - if (myPrevious != null) { - myPrevious.setNext(myNext); - } - setPrevious(anchor.getPrevious()); - if (myPrevious != null) { - myPrevious.setNext(this); - } - setNext(anchor); - anchor.setPrevious(this); - } - public int getBlankLinesBefore() { return myBlankLinesBefore; } diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsDescriptor.java b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsDescriptor.java new file mode 100644 index 000000000000..b43f5df95c65 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsDescriptor.java @@ -0,0 +1,38 @@ +/* + * 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.internal.statistic.ideSettings; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Tag; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +@Tag("setting") +public class IdeSettingsDescriptor { + @Attribute("persistent-component") + public String myProviderName; + + @Attribute("properties") + public String myPropertyNames; + + @NotNull + public List getPropertyNames() { + return myPropertyNames == null ? Collections.emptyList() : StringUtil.split(myPropertyNames, ","); + } +} diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsDescriptors.java b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsDescriptors.java new file mode 100644 index 000000000000..893b04e55aa5 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsDescriptors.java @@ -0,0 +1,30 @@ +/* + * 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.internal.statistic.ideSettings; + +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Property; + +public class IdeSettingsDescriptors { + + @Property(surroundWithTag = false) + @AbstractCollection(surroundWithTag = false) + public IdeSettingsDescriptor[] myDescriptors; + + public IdeSettingsDescriptor[] getDescriptors() { + return myDescriptors; + } +} diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsStatisticsService.java b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsStatisticsService.java new file mode 100644 index 000000000000..23cb562ef7a4 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsStatisticsService.java @@ -0,0 +1,94 @@ +/* + * 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.internal.statistic.ideSettings; + +import com.intellij.facet.frameworks.SettingsConnectionService; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.net.HttpConfigurable; +import com.intellij.util.xmlb.XmlSerializationException; +import com.intellij.util.xmlb.XmlSerializer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +public class IdeSettingsStatisticsService extends SettingsConnectionService { + private static final Logger LOG = Logger.getInstance("#com.intellij.internal.statistic.ideSettings.IdeSettingsUsagesCollector"); + private static String FILE_NAME = "ide-settings-statistics.xml"; + + private static final IdeSettingsStatisticsService myInstance = new IdeSettingsStatisticsService(); + private IdeSettingsDescriptor[] myDescriptors; + + public static IdeSettingsStatisticsService getInstance() { + return myInstance; + } + + private IdeSettingsStatisticsService() { + super("http://jetbrains.com/idea/ide-settings-statistics.xml", "http://frameworks.jetbrains.com/statistics"); + } + + @NotNull + public IdeSettingsDescriptor[] getSettingDescriptors() { + if (myDescriptors == null) { + final URL url = createVersionsUrl(); + if (url == null) return new IdeSettingsDescriptor[0]; + final IdeSettingsDescriptors descriptors = deserialize(url); + myDescriptors = descriptors == null ? new IdeSettingsDescriptor[0] : descriptors.getDescriptors(); + } + return myDescriptors; + } + + @Nullable + private static IdeSettingsDescriptors deserialize(@Nullable URL url) { + if (url == null) return null; + + IdeSettingsDescriptors ideSettingsDescriptor = null; + try { + ideSettingsDescriptor = XmlSerializer.deserialize(url, IdeSettingsDescriptors.class); + } + catch (XmlSerializationException e) { + final Throwable cause = e.getCause(); + if (!(cause instanceof IOException)) { + LOG.error(e); + } + } + return ideSettingsDescriptor; + } + + @Nullable + private URL createVersionsUrl() { + final String serviceUrl = getServiceUrl(); + if (StringUtil.isNotEmpty(serviceUrl)) { + try { + final String url = serviceUrl + "/" + FILE_NAME; + HttpConfigurable.getInstance().prepareURL(url); + + return new URL(url); + } + catch (MalformedURLException e) { + LOG.error(e); + } + catch (IOException e) { + // no route to host, unknown host, etc. + } + } + + return null; + } +} diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsStatisticsUtils.java b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsStatisticsUtils.java new file mode 100644 index 000000000000..897491532833 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsStatisticsUtils.java @@ -0,0 +1,130 @@ +/* + * 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.internal.statistic.ideSettings; + +import com.intellij.internal.statistic.beans.GroupDescriptor; +import com.intellij.internal.statistic.beans.UsageDescriptor; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.hash.HashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Set; + +public class IdeSettingsStatisticsUtils { + public static final GroupDescriptor GROUP = GroupDescriptor.create("IDE Settings", GroupDescriptor.HIGHER_PRIORITY); + + @Nullable + public static Object getApplicationProvider(@NotNull String providerName) { + return getProviderInstance(getApplicationComponentByName(providerName)); + } + + public static Set getUsages(@NotNull IdeSettingsDescriptor descriptor, @NotNull Object componentInstance) { + Set descriptors = new HashSet(); + + String providerName = descriptor.myProviderName; + + List propertyNames = descriptor.getPropertyNames(); + if (providerName != null && propertyNames.size() > 0) { + for (String propertyName : propertyNames) { + Object propertyValue = getPropertyValue(componentInstance, propertyName); + + if (propertyValue != null) { + descriptors.add(new UsageDescriptor(getUsageDescriptorKey(providerName, propertyName, propertyValue.toString()), 1)); + } + } + } + return descriptors; + } + + @Nullable + private static Object getPropertyValue(Object componentInstance, String propertyName) { + final Class componentInstanceClass = componentInstance.getClass(); + Object propertyValue = null; + try { + Field field = componentInstanceClass.getDeclaredField(propertyName); + propertyValue = field.get(componentInstance); + } + catch (NoSuchFieldException ignored) { + } + catch (IllegalAccessException ignored) { + } + if (propertyValue == null) { + Method method = getMethod(componentInstanceClass, "get" + StringUtil.capitalize(propertyName)); + if (method == null) { + method = getMethod(componentInstanceClass, "is" + StringUtil.capitalize(propertyName)); + } + if (method != null) { + try { + propertyValue = method.invoke(componentInstance); + } + catch (Exception ignored) { + } + } + } + return propertyValue; + } + + @Nullable + private static Method getMethod(@NotNull Class componentInstanceClass, @NotNull String name) { + try { + return componentInstanceClass.getMethod(name); + } + catch (NoSuchMethodException ignored) { + } + return null; + } + + private static String getUsageDescriptorKey(@NotNull String providerName, @NotNull String name, @NotNull String value) { + final String shortName = StringUtil.getShortName(providerName); + return shortName + "#" + name + "(" + value + ")"; + } + + @Nullable + public static Object getProjectProvider(@Nullable Project project, + @NotNull String providerName) { + return getProviderInstance(getProjectComponentByName(project, providerName)); + } + + @Nullable + private static Object getProviderInstance(Object componentInstance) { + if (componentInstance instanceof PersistentStateComponent) { + return ((PersistentStateComponent)componentInstance).getState(); + } + + return componentInstance; + } + + @Nullable + private static Object getApplicationComponentByName(@NotNull String providerName) { + return ApplicationManager.getApplication().getPicoContainer().getComponentInstance(providerName); + } + + @Nullable + private static Object getProjectComponentByName(@Nullable Project project, String providerName) { + if (project != null) { + return project.getPicoContainer().getComponentInstance(providerName); + } + return null; + } +} diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsUsagesCollector.java b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsUsagesCollector.java new file mode 100644 index 000000000000..e8b27c97bdad --- /dev/null +++ b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/IdeSettingsUsagesCollector.java @@ -0,0 +1,77 @@ +package com.intellij.internal.statistic.ideSettings; + +import com.intellij.internal.statistic.AbstractApplicationUsagesCollector; +import com.intellij.internal.statistic.CollectUsagesException; +import com.intellij.internal.statistic.beans.GroupDescriptor; +import com.intellij.internal.statistic.beans.UsageDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.util.containers.hash.HashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +public class IdeSettingsUsagesCollector extends AbstractApplicationUsagesCollector { + + @NotNull + @Override + public Set getProjectUsages(@NotNull Project project) throws CollectUsagesException { + Set usageDescriptors = new HashSet(); + for (Pair provider : getProviders(project, true)) { + usageDescriptors.addAll(IdeSettingsStatisticsUtils.getUsages(provider.second, provider.first)); + } + return usageDescriptors; + } + + @NotNull + private static Set> getProviders(@Nullable Project project, boolean projectComponent) { + Set> pairs = new HashSet>(); + for (IdeSettingsDescriptor descriptor : IdeSettingsStatisticsService.getInstance().getSettingDescriptors()) { + final Pair pair = getProvider(project, descriptor, projectComponent); + if (pair != null) { + pairs.add(pair); + } + } + return pairs; + } + + @Nullable + private static Pair getProvider(@Nullable Project project, + @NotNull IdeSettingsDescriptor descriptor, + boolean projectComponent) { + Object applicationProvider = IdeSettingsStatisticsUtils.getApplicationProvider(descriptor.myProviderName); + + if (applicationProvider != null) { + return projectComponent ? null : Pair.create(applicationProvider, descriptor); + } + + if (project != null) { + final Object projectProvider = IdeSettingsStatisticsUtils.getProjectProvider(project, descriptor.myProviderName); + if (projectProvider != null) { + return projectComponent ? Pair.create(projectProvider, descriptor) : null; + } + } + return null; + } + + + @NotNull + @Override + public Set getApplicationUsages() { + Set applicationUsageDescriptors = new HashSet(); + + applicationUsageDescriptors.addAll(super.getApplicationUsages()); + + for (Pair provider : getProviders(null, false)) { + applicationUsageDescriptors.addAll(IdeSettingsStatisticsUtils.getUsages(provider.second, provider.first)); + } + + return applicationUsageDescriptors; + } + + @NotNull + public GroupDescriptor getGroupId() { + return IdeSettingsStatisticsUtils.GROUP; + } +} diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/ide-settings-statistics.xml b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/ide-settings-statistics.xml new file mode 100644 index 000000000000..405f14292e99 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/internal/statistic/ideSettings/ide-settings-statistics.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index e71593736a5b..1f6d6a7799cf 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -235,6 +235,7 @@ + diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index 6000e30a1f0b..af4d5f85f11d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -44,6 +44,7 @@ import org.jetbrains.idea.svn.SvnVcs; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; +import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.wc.*; import org.tmatesoft.svn.util.SVNLogType; @@ -381,6 +382,9 @@ public class SvnHistoryProvider final SVNURL svnurl = SVNURL.parseURIEncoded(myUrl); SVNRevision operationalFrom = myFrom == null ? SVNRevision.HEAD : myFrom; final SVNURL rootURL = getRepositoryRoot(svnurl, myFrom); + if (rootURL == null) { + throw new VcsException("Could not find repository root for URL: " + myUrl); + } final String root = rootURL.toString(); String relativeUrl = myUrl; if (myUrl.startsWith(root)) { @@ -427,7 +431,12 @@ public class SvnHistoryProvider } private SVNURL getRepositoryRoot(SVNURL svnurl, SVNRevision operationalFrom) throws SVNException { - return myVcs.createRepository(svnurl).getRepositoryRoot(false); + final SVNRepository repository = myVcs.createRepository(svnurl); + final SVNURL root = repository.getRepositoryRoot(false); + if (root == null) { + return repository.getRepositoryRoot(true); + } + return root; /*final SVNWCClient wcClient = myVcs.createWCClient(); try { final SVNInfo info; diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java index d3cd58be7562..7a5645488fe9 100644 --- a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java +++ b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java @@ -217,7 +217,7 @@ public class BrowsersConfiguration implements PersistentStateComponent @Nullable final String url, final boolean forceOpenNewInstanceOnMac, String... parameters) { - DefaultUrlOpener.doLaunchBrowser(family, url, parameters, Conditions.alwaysTrue(), forceOpenNewInstanceOnMac); + DefaultUrlOpener.launchBrowser(family, url, parameters, Conditions.alwaysTrue(), forceOpenNewInstanceOnMac); } public static void launchBrowser(final @NotNull BrowserFamily family, @@ -225,7 +225,7 @@ public class BrowsersConfiguration implements PersistentStateComponent final boolean forceOpenNewInstanceOnMac, final Condition browserSpecificParametersFilter, String... parameters) { - DefaultUrlOpener.doLaunchBrowser(family, url, parameters, browserSpecificParametersFilter, forceOpenNewInstanceOnMac); + DefaultUrlOpener.launchBrowser(family, url, parameters, browserSpecificParametersFilter, forceOpenNewInstanceOnMac); } @Nullable diff --git a/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java b/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java index 260c9cc6f009..784ff1646232 100644 --- a/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java +++ b/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java @@ -42,21 +42,20 @@ public class DefaultUrlOpener extends UrlOpener { private static final Logger LOG = Logger.getInstance(DefaultUrlOpener.class); @Override - public boolean openUrl(BrowsersConfiguration.BrowserFamily family, String url) { - doLaunchBrowser(family, url, ArrayUtil.EMPTY_STRING_ARRAY, Conditions.alwaysTrue(), false); - return true; + public boolean openUrl(BrowsersConfiguration.BrowserFamily family, @Nullable String url) { + return launchBrowser(family, url, ArrayUtil.EMPTY_STRING_ARRAY, Conditions.alwaysTrue(), false); } - public static void doLaunchBrowser(final BrowsersConfiguration.BrowserFamily family, - @Nullable String url, - @NotNull String[] additionalParameters, - @NotNull Condition browserSpecificParametersFilter, - final boolean forceOpenNewInstanceOnMac) { + public static boolean launchBrowser(final BrowsersConfiguration.BrowserFamily family, + @Nullable String url, + @NotNull String[] additionalParameters, + @NotNull Condition browserSpecificParametersFilter, + final boolean forceOpenNewInstanceOnMac) { final WebBrowserSettings settings = BrowsersConfiguration.getInstance().getBrowserSettings(family); final String path = settings.getPath(); if (StringUtil.isEmpty(path)) { Messages.showErrorDialog(XmlBundle.message("browser.path.not.specified", family.getName()), XmlBundle.message("browser.path.not.specified.title")); - return; + return false; } try { @@ -65,14 +64,16 @@ public class DefaultUrlOpener extends UrlOpener { ? (additionalParameters.length == 0 ? Collections.emptyList() : new ArrayList()) : ContainerUtil.findAll(specificSettings.getAdditionalParameters(), browserSpecificParametersFilter); Collections.addAll(parameters, additionalParameters); - launchBrowser(path, url == null ? null : BrowserUtil.escapeUrl(url), forceOpenNewInstanceOnMac, parameters); + doLaunchBrowser(path, url == null ? null : BrowserUtil.escapeUrl(url), forceOpenNewInstanceOnMac, parameters); + return true; } catch (IOException e) { Messages.showErrorDialog(e.getMessage(), XmlBundle.message("browser.error")); + return false; } } - private static void launchBrowser(String browserPath, @Nullable String url, boolean forceOpenNewInstanceOnMac, List browserArgs) + private static void doLaunchBrowser(String browserPath, @Nullable String url, boolean forceOpenNewInstanceOnMac, List browserArgs) throws IOException { List command = BrowserUtil.getOpenBrowserCommand(browserPath); addArgs(command, browserArgs, url, forceOpenNewInstanceOnMac);